Removing the first node is done by changing the pointer head
for NULL
and dislocating in memory the Node that is there. An implementation that contemplates this scenario would be:
//remover à cabeça
void Remove (Lista* list){
if (list == NULL || list->head == NULL) return; //se vazia nada a fazer senão sair
No* NoARemover = list->head; //guarda um ponteiro para o nó que vai ser removido
list->head = list->head->prox; //faz o head passar a ser o seguinte
free(NoARemover); //desaloca o antigo head de memoria
list->size--; //reajusta o size para o valor correto
}
Though it’s subtle, it does answer the question:
its next and previous parameters are null [...]
Therefore, how to access n->Prox or n->ant, for n = pioneer node, in a
possible removal ?
If list->head
for NULL
the list is already empty and there is nothing left to do in a deletion. If list->head
is not NULL
then it is possible to access list->head->prox
, although this may be NULL
. And in this case is exactly what is intended because we put NULL
in the head
through this instruction:
list->head = list->head->prox; //faz o head passar a ser o seguinte
Thus passing from 1 element to none.
Edit:
with the code you gave me, I couldn’t remove the first knot
It did not do it correctly with the code I indicated, possibly because it has specific logic that had not been explained until then, or because it did not use it properly.
Here’s an example of Remove working exactly as I wrote it on Ideone
Considering the code you added in the edition:
if (atual->pos == 0 ){
and else if( atual == list->head){
are actually the same thing, assuming that their positions are incremental starting from the 0
at first.
If that’s the case then be the 0
or the head
is the same thing.
If atual
corresponds to list->head
then
list->head = atual->ant;
Corresponds to:
list->head = list->head->ant;
That as it is NULL
and equal to prox
, corresponds in fact to what I had written!
list->head = list->head->prox;
The logic for removing a middle node in a double-linked list is usually the following:
//o seguinte ao Nó a remover define como anterior o anterior do corrente
atual->prox->ant = atual->ant;
//o anterior ao Nó a remover define como o próximo do próximo do corrente
atual->ant->prox = atual->prox;
//liberta memoria do no corrente, o a remover
free(atual);
It is also important to mention that this logic will not work if the middle number is actually the last one because atual->prox->ant
crashes the program if atual->prox
for NULL
then a specific test should be made for that case, and the same happens in the code presented.
Edit 2:
Looking for the whole code indicated on ideone, I see that there are several small things that need adjustments, which is visible by the amount of warnings nominee.
However, to put it to work on the remove part just change the function to not have the first if
because it’s the same as the second one just as I indicated, and if it’s there it doesn’t do anything soon it doesn’t remove, because the removal is being done in the if
then it will no longer perform if you enter the first.
Should then stay:
if (atual != NULL){
/*if (atual->pos == 0){
}
else */if( atual == list->head){
list->head = atual->ant;
}
else {
atual->prox->ant = atual->ant;
atual->ant->prox = atual->prox;
}
free(atual);
list->size--;
}
Relevant adjustments:
The function of Busca
is making a comparison char
to char
. Simplify using strcmp
library <string.h>
. This same function is not returning NULL
when it does not find the searched text, which is something necessary for the rest of the code to work correctly.
This function could simply stay:
No* Busca ( Lista *list, char *nome){
No* ptr = list->head;
while (ptr != NULL){
//agora compara com strcmp da biblioteca de strings
if (strcmp( nome, ptr->dado.nome) == 0){ //strcmp devolve 0 quando são iguais
return ptr;
}
ptr = ptr->prox;
}
return NULL; //agora retorna NULL caso não nenhum
}
In the RemoverDados
the auxiliary nodes are no longer being used, these:
void RemoverDados ( Lista *list){
...
No* aux = (No*)malloc(sizeof(No));
No* aux1 = (No*)malloc(sizeof(No));
And so they can be removed, however, these also would not be correct in a remove function. Creating a pointer is different from creating a pointer and allocating memory to the corresponding structure.
That is to say:
No* aux; //cria só o ponteiro
It’s quite different from this:
No* aux = (No*)malloc(sizeof(No));
Which creates the pointer and allocates memory to the corresponding structure, and which is not the correct one to remove and was previously creating a memory leak. Whenever we need pointers just to navigate a list we’re not supposed to use malloc
, but only create the pointer.
In the main to make it totally correct also help to have a return, something like
int main(){
...
return 0;
}
Or using the #define
that already in stdlib.h
:
int main(){
...
return EXIT_SUCCESS;
}
Edit 3:
Trying not to make my answer too extensive (and it is already quite extensive), the biggest problem is in fact in the insertion because it does not build the previous pointers correctly. It should be as follows:
if (Busca(list, dado.nome) == NULL){
...
n->dado = dado;
n->prox = list->head;
//faltava este if para construir o ant caso não seja o primeiro
if (list->head != NULL){
list->head->ant = n; //construção do anterior aqui
}
list->head = n;
list->size++;
n->pos = p;
}
In short, we’re doing 2º->ant = 1º
. Without the former built when the RemoverDados
tries to access the previous ones do not get correct values and so simply did not work.
The RemoverDados
is also not complete, according to what I had said earlier:
It is also important to mention that this logic will not work if the
in the middle is actually the last
And to be complete must then become:
if (atual != NULL){
if( atual == list->head){
list->head = atual->prox;
}
else if (atual -> prox == NULL){ //caso que faltava para o ultimo!
atual->ant->prox = NULL; //o proximo do penultimo passa a apontar para NULL
}
else {
atual->prox->ant = atual->ant;
atual->ant->prox = atual->prox;
}
free(atual);
list->size--;
}
I understood your logic, but what I’m actually struggling to remove is the first node on the list, that is, the one that is being placed in an empty previous list.
– Paulo Bomfim
@Paulobomfim The code I indicated removes this element. If
list->head
has an element andlist->head->prox
forNULL
works perfectly by staying withlist->head
toNULL
or be empty.– Isac
as explained earlier, with the code you gave me, I was unable to remove the first node. I understood that it serves for removing head knot. I made an Edit and put the removal function to make it easier to understand, since my removal is based on a search .
– Paulo Bomfim
@Paulobomfim already edited the answer to contemplate its edition and comment.
– Isac
I understand your logic, but I can’t fit it into my code. The idea that 'pos=0' and 'list->head' are the same thing in my code is not working. (http://ideone.com/AS2gC) @Isac, I left my most complete code on Ideone, to see if you can see something. The removal fields for 'pos==0' are empty, and for some node in the middle, it is not working.
– Paulo Bomfim
@Paulobomfim , ok I re-edited according to what put in Ideone.
– Isac
I re-edited my code according to its explanations( http://ideone.com/ThNrM0 ) . Regarding
strcmp
for functionBusca
, I had already noticed this possible change. As for the statement of the auxiliary pointers, I had not noticed this issue. I’ll be leaving my code there in Ideone (including functions that are working perfectly). The intuition to leave altogether, which makes it a little more extensive, is to see if you can identify why the removal of the first or a certainNo
average, not performing as it should.– Paulo Bomfim
@Paulobomfim I edited again to fix the specific parts to the removal and others that affected the removal. I would also advise you to review the details I have indicated as for example
No* ptr = (No*)malloc(sizeof(No));
in functionOrdenaNome
, that remain in the code and are not correct.– Isac
modifications made from its new edition and working code in the foreseeable way. The whole problem really was in function
Insere
because I could not adjust the parametern->prox
for the initial n, as stated in "So, how to access n->Prox or n->ant, for n = pioneer node, in a possible removal ?"– Paulo Bomfim
@Paulobomfim I couldn’t understand what I said.
n->prox
orn->ant
to the initial node should beNULL
. In removing a "pioneer" node the relevant code executed islist->head = atual->prox;
which will actually belist->head = NULL;
sinceatual
is the only knot and soatual->prox
hasNULL
. But the code had multiple things that didn’t allow it to work properly, it wasn’t just one.– Isac
In relation to function
OrdenaNome
I’m going through the code all over, and looking at these and other details. In relation to your disagreement with my comment, I did not express myself properly : the question I was talking about, was in relation to the definition of the pioneer knot in which-prox
did not relate to the future node to be inserted (in this case, the secondno
from the list). This situation subsequently resolved by you when you said "the biggest problem is in fact in the insertion because it does not correctly build the previous pointers .. ". And yes, multiple things did not allow the operation– Paulo Bomfim