I am new to C, i am trying to learn linked lists, can some one explain me the code below.
I understand some part of it but not all of it.
void deletefrombeginning( node **head, node **tail)
{
node *temp;
if(*head==NULL)
return;
temp=*head;
if(*head==*tail)
*head=*tail=NULL;
else
{
(temp->next)->prev=NULL; <-- there is where i get lost.
*head=temp->next;
}
free(temp);
}
(temp->next)->prev=NULL;
This line is making the prev pointer of what will be your new head NULL. So that when the second item in your linked list becomes the new head with:
*head = temp->next;
it has no prev pointer and is therefore the new head.
------ ------
| | <--prev--- | |
NULL <----- | temp | | node | -----> ...
| | ---next--> | |
------ ------
Short answer:
(temp->next)->prev=NULL; makes sure that node->prev doesn't
access invalid memory.
*head=temp->next; makes temp the new head of the list.
Long answer:
You are currently at temp.
You cannot delete temp first because you then would have broken links (what would node->prev point to?).
This means you have to first remove the links related to temp.
Since temp is the first node, temp->prev should point to NULL.
So (temp->next)->prev=NULL; is equivalent to node->prev = NULL;.
We cannot directly do node->prev = NULL; because we do not know node exists at this point.
*head=temp->next makes sure that the new list head is node (in my above ascii demonstration).
The next step then frees the memory used by temp.
Tip: In case you're nitpicky like me, you might want to assign temp to NULL right after you free it. This makes sure that you can never mistakenly access temp in the rest of your code. Memory can still be accessed in error even after freeing it.
Related
I've just recently gotten into linked lists and I'm adding my own "add to end" function.
void insert_at_end(Node** head, Node* node)
{
Node* temp;
temp = *head;
if (temp == NULL) // linked list is empty
{
*head = node;
}
else
{
while (temp->pNext != NULL)
{
temp = temp->pNext;
}
temp->pNext = node;
}
}
Originally I was doing temp != NULL instead of temp->pNext != NULL because I thought that way it would take me to the very LAST node, since it stops looping when temp still has data before it reaches NULL. Wouldn't temp->pNext != NULL stop at the 2nd to last node? Since it stops looping when it realizes that the last nodes next pointer is NULL, it does not travel to that node?
Thanks guys, If I need to clear anything up from that word vomit let me know.
Wouldn't temp->pNext != NULL stop at the 2nd to last node?
No. Here is the pictorial representation for ease of understanding.
With temp != NULL, temp will be pointing to NULL:
+---+ +---+ +---+
| 1 |--->| 2 |--->| 3 |---> NULL
+---+ +---+ +---+ ^
|
temp
As you see temp is iterating until it becomes NULL, at which point you cannot attach anything to the final node because you're past it.
With temp->pNext != NULL, temp will be pointing to last node.
+---+ +---+ +---+
| 1 |--->| 2 |--->| 3 |---> NULL
+---+ +---+ +---+
^
|
temp
Here temp will iterate till its next node is NULL. That means you're pointing to the final node and you can use that pointer to adjust that node to point to a new one with temp->pNext = node:
+---+ +---+ +---+ +---+
| 1 |--->| 2 |--->| 3 |--->| 4 |---> NULL
+---+ +---+ +---+ +---+
^
|
temp
As an aside, you may also want to add the extra safety of ensuring the node you're given points to NULL, on the off chance the caller may forget to do that. That's as simple as adding this line to the start of the function:
node->pNext = NULL;
Let's make some analogy.
Each node is a station.
NULL is your stop station.
while (temp->pNext != NULL) { temp = temp->pNext; } means drive and visit each station until reach the stop station.
When you reach the stop station, an additional station is needed to be added by temp->pNext = node;
Now the former stop station followed by the new added stop station(implicitly the new NULL) is not a stop station, but the penultimate station to be visited.
have a reference for simple linked list concept
let us take an example
consider
struct node
{
int data;// data which you want to feed.
struct node *next;// gona hold the address of the next data, so that link can be established
}*root,*p; // root is the starting reference to your linked list
case 1: you dont insert any element and your linked list is empty. Now when you insert a new data 10.it will check for any data in the global pointer reference to your linked list, if, the pointer seems to be NULL, then it means your liked list is empty.The memory stack will be created like this.
10
1000
10 is the data, 1000 is its address.
case 2: adding an element at its back.you want to add, data 20 to your linked list.you will be looking whether the linked list is empty or not first, using your global linked list address reference(it will be a pointer variable, holding your linked list 1st address, as per your code)
now when we see root->data is not null 1000->data is 10
we go for root->next which is null, which we come to know that this is the last node. 1000->next is NULL
and we insert the new node address to the root->next so that a link is created to the newly inserted node.
stack will be created like this
10 20
1000 1004
case3: now you want to add another data say 30 to the end of list again. just follow the same as case 2.
check for the node which is currently null, i.e root->next == NULL,
for this you use a loop to find the node which is currently in last, like this.
struct node *temp; // creating a temp node which will be the new node we will insert
temp = (struct node *)malloc(sizeof(struct node));// allocating the size for the temp node, same as the size of previous nodes.
p = root;// i am giving my starting address to pointer p, i traverse the node with pointer p only, since i dont want to loose my root starting address.
while(p->next != NULL)// checking for the last node
p = p->next;// if last node not found, just move to next node, and see whether it is last node or not
p->next = temp;// if last node is found, put the address of newly created temp node to the node previously found last in the linked list.
temp->data = element;// feeding data to the temp node.
temp->next = NULL;// keeping temp node as last, it is necessary to say temp wont has any more node connected.
NOTE dont think this is just a temp node, and will disappear once we come out of function, it is playing with pointer, so it wont destroyed until, the owner wont destroy it.
flow will be
newly created temp address is 1008
1000->next is 1004
1004->next is NULL
so, 1004->next will hold 1008 now
then,1008->data will be 30
then, 1008->next will be NULL
stack will be created like this
10 20 30
1000 1004 1008
Could someone please explain to me how this code works. I tried writing it out and wrapping my head around it, but I am still lost.
When you are setting next->prev = prev what is the difference in value between next->prev and prev? aren't they the same value? same question for the next line as well.
I tried writing out a ListElement struct to try to help understand but I am still confused. Any answer or help would be greatly appreciated, or any other references that can make me understand. I am a visual learner so if you happen to know a good visualization of this, I would appreciate it.
int unlink(ListElement *element)
{
ListElement *next = element->next;
ListElement *prev = element->prev;
next->prev = prev;
prev->next = next;
return 0;
}
The first two assignments define "connections" to the previous, 1, and next, 3, node.
ListElement *next = element->next; // next connects current node to the one that follows
ListElement *prev = element->prev; // prev connects current node to the one that precedes
that is why they are called prev and next. The other two lines are re-wiring the prev and next nodes such that they skip the current node, i.e.
you are accessing the preceding and following nodes's members (with the same names) via the connections defined above:
next->prev = prev; // now node: 3 is connected to node: 1
prev->next = next; // now node: 1 is connected to node: 3
Note: remember that each node has two pointers named prev and next
Let's say you have a linked list:
1->2->3
Pointer head points to the head of the list.
head->next points to the element 2.
*
1->2->3
You call method unlink on it:
unlink(head->next);
By passing head->next, you passed element 2 to the function.
It will then keep pointers to the next and previous elements:
ListElement *next = element->next; //3
ListElement *prev = element->prev; //1
It will then proceed to unlink this element:
next->prev = prev; // now next (3) has a previous pointer to 1
prev->next = next; // now prev (1) has a next pointer to 3
Now 2 is unlinked and can be reused/deleted.
This code removes an element from a doubly linked list.
It is done by assigning the "next" pointer of element's previous element directly to element's next element. Vice versa, the "prev" pointer of element's next element is set to element's previous element.
This has the effect that element is removed from the linked list.
Hope this helps.
When you are setting next->prev = prev what is the difference in value
between next->prev and prev? aren't they the same value?
This only sets the pointer next->prevto the value of prev, meaning that the next element's prevpointer points to the same address as the variable prev.
This function basically unlinks passed list element.
No, they don't have the same value.
prev->next is the next pointer of the node before element in the list.
next is defined as element->next, so it a pointer to the node after element in the list.
So, with prev->next = next, you basically set the next pointer of the node before element to the node after element.
Analog explanation for next->prev = prev.
This diagram from the UCLA illustrates the behavior of your function:
Let's draw a diagram of the doubly linked list's elements:
|ITEM0 | |ITEM1 | |ITEM2 |
| next->ITEM1 | | next->ITEM2 | | next->NULL |
| prev->NULL | | prev->ITEM0 | | prev->ITEM1 |
Let's say we want to unlink ITEM1, we save the next element into a variable called next, that's the *next = element->next; part, so now next = ITEM2, then we save the previous: *prev = element->prev;, so now prev = ITEM0. Now, we set the previous of the next element (aka previous of ITEM2) to prev (which is ITEM0) and set the next of the previous (aka next of ITEM0) to next (which is ITEM2), so we end up with this:
|ITEM0 | |ITEM1 | |ITEM2 |
| next->ITEM2 | | next->ITEM2 | | next->NULL |
| prev->NULL | | prev->ITEM0 | | prev->ITEM0 |
Note how we moved the next pointer of ITEM1 into the next pointer of ITEM0, and the prev pointer of ITEM1 into the prev pointer of ITEM2.
At this point, we can free ITEM1 (as nothing points to it), and we have just unlinked it from the linked list!
I have a question, if I wish to delete a node from linked list and I do this :
Assume: Head points to first node.
deleteFirstNode(struct node * head)
{
struct node* temp=head;//this line
temp->next=head->next->next;
temp->data=head->next->data;
free(head);
head=temp;
}
1) will this delete first node?
2) If so, when I free head , will it not free temp pointer too? because both temp and head point to same location in this line (see comment in "this line" in code).
If both above are true, how will I retain retain pointer to beginning of the list. ?
Thank you very much.
i would pass a double pointer and do something on these lines
deleteFirstNode(struct node ** head) {
struct node* temp= *head;
*head = temp->next;
free(temp);
}
You want to delete the node that head points to; you have several problems:
1) you pass in a copy of the head pointer - the function is unable to change the original head pointer the function was called with, so the last line of the function, head=temp does nothing really. When the function returns whatever you had pointing to the first node on the list will now be pointing to freed memory. In effect, you have lost the list.
2) when you're grabbing head->next->data you're not getting the data item you want because head->next has been overwritten.
3) free(head) will also free temp since it points to the same thing as head. temp is kind of pointless.
Some notes in the code:
deleteFirstNode(struct node * head)
{
struct node* temp=head;
temp->next=head->next->next; // note: this overwrites head->next
temp->data=head->next->data; // so this gets what used to be
// head->next->next->data
free(head); // this frees `temp` (which is an alias for `head`)
// - so whats the point of `temp`?
head=temp; // this is pointless in more ways than one
}
So here's a proposed (untested) alternate version of deleteFirstNode():
deleteFirstNode(struct node ** head)
{
struct node* temp = *head; // temp points to the node we want to free
struct node* next = temp->next; // next points to what will be the new
// first node
free(temp);
*head=next;
}
You will have to call the function by passing in a pointer to the head pointer:
struct node* head_pointer;
// ...
deleteFirstNode(&head_pointer);
Another thing to consider:
if your head pointer is NULL, deleteFirstNode() will not work. You should make it handle that case.
will this delete first node?
Yes.
If so, when I free head , will it not free temp pointer too? because both temp and head point to same location in this line (see
comment in "this line" in code).
Yes, it will free the memory pointed by temp too as both head and temp are pointing to same memory. Pointer head will be pointing to an invalid memory location after this method is executed.
Yes you have two pointers pointing to the same address.
So deallocating memory by calling free() on either of them will free the pointed memory.
EDIT:
For understanding Link lists always draw them on piece of paper.
------------- ------------ -----------
| | | | | |
| head |----->| first |------>| second |
| | | | | |
------------- ------------ -----------
Steps you need to do are:
Isolate first.
Make head point to Second.
free first.
temp = head->next; //temp now points to first
head = temp->next; //head now points to second
free(temp);
From your suggestions above here is my final code to delete first node and return pointer to head node (which will be second node in list).
struct node* freeFirstNode(struct node* head)
{
struct node* temp;
temp=head//edited after expert's comment
temp->next=head->next;//please confirm if this is valid and not Bad pointer.
temp->data=head->data;
free(head);//how will I fix this? it will free temp too.
return(temp);
}
I am working on my homework but I really don't know how to remove a node with an integer data I already have a code for adding of nodes, I just need to remove nodes, or can you give me atleast an algorithm of it goes like this
addnode(root,5);
addnode(root,2);
addnode(root,6);
display(root);
removenode(root,5);
display(root);
removenode(root,6);
do you guys need code for my addition code? but our proff already gave us the code for showing the display of nodes ;
void display(struct node *head)
{
struct node *traverser;
traverser = head;
while(traverser!=NULL)
{
printf("%d\n",traverser->x);
traverser=traverser->next;
}
}
struct node
{
int data;
struct node *next
};
a question though what does traverser=traverser->next;
I assume you are dealing with a linked list. These are usually built up of entries that contain data and a link to the following name (thus the name):
struct node {
int data;
struct node *next;
}
As you can see, the link is a pointer in C. Which should point to the next entry. To start traversing a list, you usually have got a head.
If you want to remove an entry, you need to traverse the list and once you found the entry you want to remove, simply rearrange the pointers:
void removeEntry(int data, struct node *head) {
struct node *prev = NULL, *current = head;
while(current->data != data) {
prev = current; // current will always point to the entry in front of current
current = current->next;
if(current == NULL) // end of list and no match
return;
}
// now current is pointing to the entry you want to remove
// remove it just by rearrangeing pointers
prev->next = current->next;
free(current); // I assume you malloc'ed the memory
}
Note: Please note that I omitted errorchecking here. Also, sometimes the head is a fixed item in which no data is stored (would work in my case), sometimes head can contain data itself (in this case you need to check if the element you want to remove is the first element and relink head accordingly)
1)
you can delete the node from the linked list like(considering head is not dummy node i.e head also contains data)...
int flag=0;
if(head->data==data_todel) head=head->next; //if head contains the data
ptr=head;
while(ptr->next!=NULL && flag==0)
{
if(ptr->next->data!=data_todel)
ptr=ptr->next;
else
{
flag=1;
break;
}
}
if(flag) ptr->next=ptr->next->next;
you need to use two pointers to free the deleted node.
2)
+------+-------+ +------+-------+
| data1| next | | data2| next |
+------+-------+ +------+-------+
^ | ^
| | |
| +--------------+
+---------+
|traverser|
+---------+
after traverser=traverser->next
+------+-------+ +------+-------+
| data1| next | | data2| next |
+------+-------+ +------+-------+
| ^ ^
| | |
+--------------+ |
|
+---------+
|traverser|
+---------+
that means it is assigning the address of of the next node currently pointed by traverser.
a question though what does traverser=traverser->next;
It sets the pointer to the next element in the queue. Iterating in your while cicle until it reaches a null pointer (end of the queue).
(You didn't post the node structure declaration, so i'm just guessing)
The next field is the key in the linked list. Each element has a successor, that way the list is linked. So, when you traverse the list, you start at the first element head and move from one element to the next until there is no next element.
To remove an entry, you need to cycle through the list until you find that entry. Then, set the next variable of the previous entry to the next entry. That way, the element is removed from the list.
I have been working with a doubly linked list. Everything works OK with the exemption of the function that should add a copy of 'who' before 'whereX' [see code bellow]. Why is the function not working?
void addNodeAt(Node *whereX, Node *who)
{
//copy
Node *temp = (Node*)malloc(sizeof(Node));
temp->count = who->count;
strcpy(temp->word,who->word);
temp->before = whereX->before;
temp->after = whereX;
//paste
if(whereX->after == who)
whereX->after = who->after;
whereX->before = temp;
}
EDIT:
In response to user326404 who said:
'Note: Your function does suffer a flaw that prevents it from inserting who as the new head of the list. It will insert, but you never return the new head node so the list is lost.'
what if I have a Node *head as a global variable. How can I reasign the head without returning it?
You are not letting the existing links know about the newly created temp node. Add the following code to the end of the function to let the preceding portion of the chain point to the newly created node.
if (whereX->before != NULL)
whereX->before->after = temp;
Note: Your function does suffer a flaw that prevents it from inserting who as the new head of the list. It will insert, but you never return the new head node so the list is lost.
Let's say you have this list:
[Node1] <-> [WhereX] <-> [Node2]
From these assignments:
Node *temp = (Node*)malloc(sizeof(Node));
temp->count = who->count;
strcpy(temp->word,who->word);
temp->before = whereX->before;
temp->after = whereX;
and from this:
whereX->before = temp;
you will have:
[Node1] <- [temp] <-> [WhereX] <-> [Node2]
| ^
----------------------
but Node1's after pointer is still looking at WhereX, so
you should also add this assignment:
whereX->before->after = temp;
What you are doing needs some changes. You have correctly allocated memory to duplicate.
But problem statement is not very clear.
Assuming you want to add a node before whereX, you have to do the following:
Point "after" pointer of temp to whereX
Point "before" pointer of temp to "before" pointer of whereX
Point "before->after" pointer of whereX to temp
Point "before" pointer of whereX to temp
Hope this helps.
EDIT:
Also do the appropriate NULL checks