how to insert node in Circular Linked list in C - c

Can someone explain the 'while part' of the code?- in the main() head is declared as struct node pointer initialized with value NULL. and a node is inserted by calling function = push(&head,12)
void push(struct Node **head_ref, int data)
{
struct Node *ptr1 = (struct Node *)malloc(sizeof(struct Node));
struct Node *temp = *head_ref;
ptr1->data = data;
ptr1->next = *head_ref;
if (*head_ref != NULL)
{
while (temp->next != *head_ref)
temp = temp->next;
temp->next = ptr1;
}
else
ptr1->next = ptr1; /*For the first node */
*head_ref = ptr1;
}

Can someone explain the 'while part' of the code?
The while() part (also described in section 2.) below.) is to look for the node which points to the current head node so that the new node can be inserted just before it. While in the loop, notice that as nodes are found, and they are not yet the head node, they are incremented so as to prepare for the insertion when head node is finally located.
The last expression in the routine:
*head_ref = ptr1;
Is to handle the case described by section 1.) in the general steps below.
General approach for the following initial conditions:
Linked List is empty:
a) since new_node is the only node in CLL, make a self loop.
new_node->next = new_node;
b) change the head pointer to point to new node.
*head_ref = new_node;
New node is to be inserted just before the head node:
(a) Find out the last node using a loop.
while(current->next != *head_ref)
current = current->next;
(b) Change the next of last node.
current->next = new_node;
(c) Change next of new node to point to head.
new_node->next = *head_ref;
(d) change the head pointer to point to new node.
*head_ref = new_node;
New node is to be inserted somewhere after the head:
(a) Locate the node after which new node is to be inserted.
while ( current->next!= *head_ref &&
current->next->data data)
{ current = current->next; }
(b) Make next of new_node as next of the located pointer
new_node->next = current->next;
(c) Change the next of the located pointer
current->next = new_node;
Details and implementation for doing this are shown in this example code

Related

C - can't prepend a linked list

I'm following the tutorial over here to build a linked list. I can't get the "Adding an item to the beginning of the list (pushing to the list)" part to work.
My code:
node_t* prepend(node_t **head, int val) {
//create new node pointer
node_t *new_node = (node_t*) malloc(sizeof(node_t));
new_node->val = val;
new_node->next = *head; //set its next to existing head (pointer of pointer)
//update existing head to point to new node
*head = new_node;
return *head;
}
int my_first_ll() {
//define a local variable called head that will point to the first node
node_t *head = NULL;
head = (node_t*) malloc(sizeof(node_t));
//check for null pointer
if (head == NULL) {
return 1;
}
//note how because head is a pointer we're using -> rather than dot notation to access attributes
head->val = 1;
head->next = (node_t*) malloc(sizeof(node_t));
head->next->val = 2;
head->next->next = NULL; //last item should point to a NULL
head = prepend(head, 0);
print_list(head);
}
It prints:
Currently at node 0
Instead of
Currently at node 0
Currently at node 1
Currently at node 2
So it seems when I insert the new head I fail to link to the previous one - but I just can't figure out how.
I found a solution: instead of passing **head to prepend like they do in the tutorial, passing *head solves it. Thus the final code:
node_t* prepend(node_t *head, int val) {
//create new node pointer
node_t *new_node = (node_t*) malloc(sizeof(node_t));
new_node->val = val;
new_node->next = head; //set its next to existing head (pointer of pointer)
//update existing head to point to new node
head = new_node;
return head;
}
Could someone explain why one works and the other doesn't? And why did they use two stars in the tutorial? And if two stars is actually correct, then why is it failing for me?
You can pass **head to the function, so you basically pass a pointer to a pointer:
void prepend(node_t **head, int data){
node_t *new = malloc(sizeof(node_t));
//set data
new->data = data;
//set the next pointer of new to current head
new->next = *head;
//now set the newly created node to be the new head
*head = new;
}
But the you'd have to call the function like this:
int main()
{
node_t *head = NULL;
prepend(&head, 3);
prepend(&head, 6);
printlist(head);
deltelist(&head);
return 0;
}
And theres no reason to return the *head in your function because you basically change the head node you created in main.
So if I now print my list, it prints
6
3
And never forget to delete the list after you used it.
Hope this helped you :)

Why does my code not insert a new node into this linked list?

I am new to programming. I just want to know why this doesn't work.
My understanding of pointers isn't clear, especially when using pointers across functions.
void append(struct Node** head_ref, float new_data)
{
struct Node* new_node = (struct Node*) malloc(sizeof(struct Node));
struct Node *last = *head_ref; /* used in step 5*/
new_node->data = new_data;
new_node->next = NULL;
while (last != NULL)
last = last->next;
last = new_node;
return;
}
void append(struct Node** head_ref, float new_data)
{
while (last->next != NULL)
last = last->next;
last->next = new_node;
return;
}
In the first function the new data doesn't get included, I get only the original linked list.
But the second function works just fine. How does a double pointer work when inserting a new node in the beginning of the linked list? (I have seen answers regarding this question, but I am still confused)
In the first example, you move the pointer last until it points at a NULL location. Then, you set the pointer to new_node. However, at this point, last has no real association to your linked list. It is just a pointer to some memory. In the second example, the correct one, you iterate until you reach the tail of the linked list, where next of that node is NULL. Then, you set that next to new_node. There is now a new tail to the list, that is new_node.
Changing the local variable last does not change the value of the data member next of the previous (last) node.
To be more clear let's assume that the list is empty. Then you have to change the pointer referenced by this double pointer head_ref.
You declared a new pointer
struct Node *last = *head_ref;
The loop
while (last != NULL)
last = last->next;
is skipped because now already last is equal to NULL die to the initialization in the previous declaration. And then you changed this local variable last
last = new_node;
The original value of the pointer pointed by head_ref was not changed because last and *head_ref occupy different extents of memory. You changed the memory occupied by last but not changed the memory occupied by head_ref.
Also you should check whether a memory was successfully allocated.
The function can look the following way
int append( struct Node **head_ref, float new_data )
{
struct Node *new_node = malloc( sizeof( struct Node ) );
int success = new_node != NULL;
if ( success )
{
new_node->data = new_data;
new_node->next = NULL;
while ( *head_ref != NULL ) head_ref = &( *head_ref )->next;
*head_ref = new_node;
}
return success;
}
As for this loop (I think you wanted just to show the loop not a whole function)
while (last->next != NULL)
last = last->next;
last->next = new_node;
then you are changing the data member next of the previous (last ) node.
Though this loop will not work if initially head_ref is equal to NULL.

Delete last node of single linked list using tail pointer

I'm creating a singly linked list in C which has head and tail pointers where the head pointer points to starting node of SLL and tail pointer points to the last node of SLL. I don't want to traverse till the end of the list using the head pointer to delete the node. Is there a way so that I can use the tail pointer to delete the last element of SLL?
Following is node addition function. head and tail are initiated NULL.
void add_node_last(Node** head, Node** tail, int data) {
Node* new_node = (Node *) malloc(sizeof(Node));
new_node -> data = data;
new_node -> ptr = NULL;
if(*head == NULL && *tail == NULL) {
*head = new_node;
*tail = new_node;
return;
}
(*tail) -> ptr = new_node;
*tail = new_node;
}
To delete the first node, the following function is used:
void del_first(Node **head) {
if(*head == NULL) {
return;
}
*head = (*head) -> ptr;
free(*head);
}
You can free the node's memory, but only once. After the first removal, your tail pointer, and the ptr of the second to last node, will be invalid pointers. In order to make sure both pointers are always correct you either need to traverse the entire list or make it a doubly linked list.
That's a long way of saying no (thanks to #stark).
in order for this to work without making it a doubly linked list, you could have the tail's *next pointer point to the head of the list, then traverse through it till you reach the node before the tail. once there you can NULL its *next pointer which would essentially detach the original tail from the list. you would then set the tail to the current node, then finally free the original tail.
void del_last(Node **head, Node **tail) {
struct node *new_head = *head;
struct node *current = *tail;
current->next = head;
while(current-> != *tail) //getting the node right before the original tail
{
current = current->next
}
current->next = NULL; //detaches original tail form list
free(**tail); //gets rid of original tail
**tail = current; // sets current node to tail pointer
}

Why does this pointer get assigned while copying a linked list?

In this code:
Node *CopyList(Node **head) {
Node *current = *head;
Node *NewNode = NULL;
Node *tail = NULL;
while (current != NULL ) {
if (NewNode == NULL) {
NewNode = malloc(sizeof(Node));
NewNode->data = current->data;
NewNode->next = NULL; // routine
tail = NewNode;
} else {
tail->next = malloc(sizeof(Node)); // here
tail = tail->next;
tail->data = current->data;
tail->next = NULL;
}
current = current->next;
}
return(NewNode);
}
Why are we assigning tail->next to the result of a malloc() call? Evidently, if we don't do so a segmentation fault occurs.
Why didn't we just allocate tail instead of tail->next? What are some situations in which I should allocate next like this?
It is just a convenience, to avoid an extra variable:
Node* temp = malloc(sizeof(Node)); // here
temp->data = current->data ;
temp->next = NULL ;
tail->next = temp ;
tail = tail->next;
Why we didn't just allocate tail instead tail->next ?
Tail is already allocated, it is acting as the previous node, so we can link it to the next one. We allocate a new node and link tail to that node with tail->next = that_node.
here NewNode represents New Linked list head. So for the first time in while loop it gets allocated so it's not getting changed next time onward. Coming to your question that 'tail->next' instead of 'tail' because for the first time when 'NewNode == NULL' then 'tail = NewNode' gets executed means tail is having NewNode address. So next onward you need to copy next block into 'tail->next' as tail is already having 'NewNode'.

Adding nodes to end of a linked list in C

The code I have is adding nodes to head but I want them added to tail. I tried pointing head to next node to null but it stops since the next node is null
if(head==NULL)
{
head=node;
}
else
{
node->next=head;
node->prev=NULL;
head->prev=node;
head=node;
}
printf("The node is inserted to linked list succesfully. \n\n");
printMenu();
You need to keep a pointer to your list's tail, and then adding an element may look like:
node -> next = NULL;
tail -> next = node;
node -> prev = tail;
tail = node;
You need to go to the end of the list first:
if(head==NULL)
{
head=node;
}
else
{
struct nodetype *p = head;
while (p->next)
p = p->next;
p->next = node;
node->prev = p;
}
// Create new node
struct nodeType *newNode = (struct nodeType *)malloc(sizeof(struct nodeType));
// Singly-linked list and new node is end of the list so the next pointer is NULL
newNode->next = NULL;
if(head==NULL){
// If head is not assigned
head = newNode;
}
else{
// Assign the next pointer in the current node to the new node
current->next = newNode;
}
// Update the current pointer to point to the newNode
current = newNode;
where head and current is,
struct nodeType *head, *current;
If the current pointer does not point to the end of the list you can iterate over the list to the end with the following line and then start appending to the linked-list:
for(current = head; current->next != NULL; current = current->next);

Resources