Doubly Linked List Pointer Confusion - c

Below is the code for inserting a node in a doubly linked list.
struct dllist
{
int data;
struct dllist *prev, *next;
};
void DLLInsert(struct dllist **head, int position, int data)
{
int k = 1;
struct dllist *temp, *newNode;
newNode = (struct dllist *)malloc(sizeof(struct dllist));
if (!newNode)
{
printf("Memory Error\n");
}
newNode->data = data;
if (position == 1)
{
newNode->next = *head;
newNode->prev = NULL;
*head = newNode;
return;
}
else
{
temp = *head;
while (temp->next != NULL && k < position - 1)
{
k++;
temp = temp->next;
}
if (temp->next == NULL)
{
temp->next = newNode;
newNode->prev = temp;
newNode->next = NULL;
}
else
{
newNode->prev = temp;
newNode->next = temp->next;
temp->next = newNode;
temp->next->prev = newNode;
}
}
}
I am getting somewhat confused in the underlying pointer operations being a newbie. A **head is passed onto the function to modify it. But in case when the position>1, a copy of *head(temp) is used to modify the list compared to the case when position==1. Can anybody explain me why is it so?
Thanks

When position > 1, temp is set to *head, and the code iterates temp through the linked list to the node at index position. Effectively, you are modifying the node at index position.
When position = 1, you are modifying the head node, so you don't need to iterate.

In the case of position==1, your new element will become the new head. You already know exactly where it is. Otherwise, you need to find the position.
temp = *head;
while (temp->next != NULL && k < position - 1)
This is used to iterate through the list until you find the element in the position you are going to insert at.
temp = temp->next;
The first element you assign to temp is head, but it is replaced with the next element in each iteration.

Related

C programming - Reverse a linked link by iterative method

I am trying to reverse a linked by iterative method. Magically, after watching tutorial and trying to recode myself, the program works successfully. However, when I review the code, I hit a question: in line 23, why we must use temp1->next instead of temp1? When traversing to the end of the linked list, which case we use the condition (the node != NULL)? In which case we use (the link of the node ! = NULL)? I fully appreciate it if anyone can enlighten me.
#include <stdio.h>
#include <stdlib.h>
struct Node
{
int data;
struct Node* next;
};
struct Node* Insert(struct Node* head, int data)
{
struct Node* temp = (struct Node*) malloc(sizeof(struct Node));
temp->data = data;
temp->next = NULL;
//If the list is empty
if (head == NULL)
{
head = temp;
}
else //The list is not empty
{
struct Node* temp1 = head;
while (temp1->next != NULL)
{
temp1 = temp1->next;
}
temp1->next = temp;
}
return head;
}
void Print(struct Node* head)
{
struct Node* temp = head;
while (temp != NULL)
{
printf("%d ", temp->data);
temp = temp->next;
}
printf("\n");
}
struct Node* Reverse(struct Node* head)
{
struct Node* *prev, *current, *next;
current = head;
prev = NULL;
while (current != NULL)
{
next = current->next;
current->next = prev;
prev = current;
current = next;
}
head = prev;
return head;
}
int main()
{
struct Node* head = NULL;
printf("Enter the length of the linked list you want to create: ");
int length;
scanf("%d", &length);
printf("Enter the value you want to input: ");
int i;
for (i = 0; i < length; i++)
{
int x;
scanf("%d", &x);
head = Insert(head, x);
}
printf("Given linked list\n");
Print(head);
head = Reverse(head);
printf("\nReversed linked list \n");
Print(head);
return 0;
}
In that case, inside the while condition, on line 23, you can notice that the program is using temp1 = temp1->next, if you change the condition to temp1 != NULL when it reaches the last element of linked list it'll collect trash from memory or even result in an error, because NULL don't have a next position.
So, you use temp1 != NULL if you are accessing the data inside the list and temp1->next != NULL if you are manipulating the next positions of the linked list.
Because temp1->next at the end of the linked list is NULL, however, the last node has data, if you use temp1 == NULL you would say that the last node is NULL, which is not the case. So you want to end the loop when the "pointer to the next node" is NULL, not when the next node is NULL.

Appending a new node to linked list

Basically what title says, Im trying to append (add to end of my list). my BuildList function takes in a size parameter that determines how many nodes the list will have. my problem is with my append function. So if I have 5 as my head, how do I fix my append function so that random numbers will be added after 5?
typedef struct Node
{
int value;
struct Node* next;
} Node;
Node *createNode( int num )
{
Node *ptr;
ptr = (Node *) malloc( sizeof( Node ) );
ptr->value = num;
ptr->next = NULL;
return ptr;
}
Node* append (Node* head, Node* newNode)
{
if (head == NULL)
return newNode;
while (head -> next != NULL);
head -> next = newNode;
return head;
}
Node* buildList (int size)
{
Node* newNode = (Node*) malloc (sizeof(Node));
Node* head = NULL;
for (int i = 0; i < size; i++)
{
Node* newNode = createNode (rand () % 10);
head = append (head, newNode);
}
return head;
}
Well, the most glaring issue is this
while (head -> next != NULL);
I believe you meant to write something like this
Node *tmp = head;
while (tmp -> next != NULL) {
tmp = tmp->next;
}
tmp->next = newNode;
You don't want to modify head here since you return it later in the function. If you didn't use tmp, head would always point to the penultimate node in the list.
You just need to modify your while, why do you have an empty instruction there? If the head is not NULL then you will never exit:
while (head -> next != NULL)
{
head = head -> next;
}

Adding a node to the head of the linked list

I would like to add a node in a sorted linked list based on the number. This is the struct:
struct node {
int number;
struct node *next;
}
I am able to add to the sorted linked list correctly but can't get it to change head.
Unfortunately I can't change the format of the function declaration so this is my function:
int create(struct node *head, int number) {
struct node *newNode = malloc(sizeof(struct node));
newNode->number = number;
struct node *current = head;
if (current->number == -1) {
newNode->next = NULL;
*head= *newNode;
return 1;
}
//Checking if head's number is bigger than init
if (current->number > number) {
newNode->next = current;
*head = *newNode;
} else {
while(current->next != NULL && (current->number <= number)) {
current = current->next;
}
newNode->next = current->next;
current->next = newNode;
}
return 1;
}
the call to the function is (Note I also can't change this):
struct node *list;
list = initializeList();
int num;
num = create(list, 5);
num = create(list, 1);
After the second call, the list should be 1->5. But it becomes 1->1->1->1->.....
Edit: Code to Initialize list:
struct node * initializeList() {
struct node *head;
head = malloc(sizeof(struct node));
head->next = NULL;
head->number = -1;
return head;
}
I made a few edits to the create function to fix the problem.
First, if the head of the list has number == -1 then no new node should be allocated, since you are just replacing the number.
Second, if you need to insert a node, the previous node needs to know where to the next node goes, so you can't just replace the previous node with the new node. You need to either point the previous node to the new node and point the new node to the displaced node; or you can copy the current node into the new node, and put the number for the new node into the current, and point it to the new node. The second works better here, since it does not require changing the head (which we can't do if it needs to go at the front).
int create(struct node *head, int number) {
struct node *current = head;
if (current->number == -1) {
current->number = number;//just replace the number, no need for anything else
return 1;
}
//allocate only if we must insert
struct node *newNode = malloc(sizeof(struct node));
//no longer need to check if head
while(current->next != NULL && (current->number <= number)) {
current = current->next;
}
if(current->next == NULL && current->number < number) {//check if number needs to go at the end
current->next = newNode;
newNode->next = NULL;
newNode->number = number;
} else {
*newNode = *current;//newNode will go after current, but with current's values
current->number = number;//replace current with the number to "insert" it
current->next = newNode;//point to the next node
}
return 1;
}
assign an index value to the node and shift the other elements by one. I mean you can add one to the each value of the other element and make in iterate in a loop.

Insert a number to a sorted linked list, why the number inserts to the second position every time?

I am working on a project about linked list, I have trouble with inserting a number to a sorted linked list. The number inserted to the second position every time, I cannot figure out where the problem is.Here is my code:
void insertSort(struct linkedList *n,int num,int *length){ //insert number to a sort linked list
node *new = (node *) malloc(sizeof(node)); //create a new node
new->next=NULL;
new->data = num;
while(n!=NULL&&n->data > new->data){ // find which position num should insert in sorted list
n = n->next;
}
new->next = n->next;
n->next= new;
length += 1;
}
n is head of the linked list. I initialized head points to the first node and has not value.
Here is how I call this function:
insertSort(head->next,num,&length);
The number inserted to the second position every time. Like I want to insert 45 into sorted linked list <16,32,72,81,97>, after inserting, the list would be <16,45,32,72,81,97>. 45 inserts to the second position for some reason.
The problem :
The number inserted to the second position every time...
is occurring because in this part of code:
while(n!=NULL&&n->data > new->data){ // find which position num should insert in sorted list
n = n->next;
}
new->next = n->next;
n->next= new;
you are inserting the new node after the n->next.
Assume the first node of your linked list is having data 16 and now you want to insert the new node with data 45 in the linked list, the while loop condition will fail as 16 > 45 will evaluate to false.
And the statement after while loop new->next = n->next; will set the next of new node to next of the first node and n->next= new; will insert the new node after first node. Hence, the new node inserted to second position every time.
There are few more problems with your function insertSort() like:
It does not track the head of the linked list while inserting a node to the linked list and,
What will happen if the node inserted is the first node of the linked list? In that case n will NULL and in insertSort() after while loop it is accessing next of n - new->next = n->next;.
Looking at the example you have given - <16,32,72,81,97>, you want to insert in ascending order.
You can do:
struct linkedList *insertSort(struct linkedList *n, int num, int *length) {
struct linkedList *first_node = n;
struct linkedList *new_node = malloc(sizeof(struct linkedList)); //create a new node
new_node->next=NULL;
new_node->data = num;
if (first_node == NULL || first_node->data >= new_node->data) {
new_node->next = first_node;
first_node = new_node;
} else {
struct linkedList *temp = first_node;
while (temp->next != NULL && temp->next->data < new_node->data) {
temp = temp->next;
}
new_node->next = temp->next;
temp->next = new_node;
}
*length += 1;
return first_node;
}
Here, you can see that I have changed return type void to struct linkedList * so that after inserting new node to appropriate location in linked list insertSort() will return the head of the linked list. That way you can keep track of head of linked list after every insertion. You just need to do:
head = insertSort(head, num, &length);
from wherever you are calling insertSort().
Alternatively, you can pass the address of head pointer in insertSort() and keep track of it, if you don't want to change the return type of insertSort(), like this:
void insertSort(struct linkedList **head, int num, int *length) {
struct linkedList *new_node = malloc(sizeof(struct linkedList)); //create a new node
new_node->next=NULL;
new_node->data = num;
if (*head == NULL || (*head)->data >= new_node->data) {
new_node->next = *head;
*head = new_node;
} else {
struct linkedList *temp = *head;
while (temp->next != NULL && temp->next->data < new_node->data) {
temp = temp->next;
}
new_node->next = temp->next;
temp->next = new_node;
}
*length += 1;
}
You can call insertSort() like this:
insertSort(&head, 32, &length);
Hope this helps.
because you are never testing the position of the node . your code only puts the new node at 2nd position . it does not checks where it should be in the sorted list
try below
void sortedInsert(struct Node** head_ref, struct Node* new_node) {
struct Node* current; /* Special case for the head end */
if(*head_ref == NULL || (*head_ref)->data >= new_node->data) {
new_node->next = *head_ref;
*head_ref = new_node;
}
else {
/*Locate the node before the point of insertion */
current =*head_ref;
while (current->next!=NULL && current->next->data < new_node->data)
{
current = current->next;
}
new_node->next =current->next;
current->next = new_node; }
}

insert element at nth position in the linked list - C

my program shows list is empty. I think I'm making mistake on re-linking the nodes to the head. Help me figure it out.
void insert(struct node** headRef, int index, int Data)
{
int i, distanceFromHead = 1;
struct node* head = *headRef;
struct node* temp1 = (struct node*)malloc(sizeof(struct node)); //node to be inserted.
temp1->data = Data;
if(index == 0)
{
temp1->next = head;
head = temp1;
return;
}
while(head != NULL)
{
if(distanceFromHead == index)
{
temp1->next = head->next;
head->next = temp1;
*headRef = head;
return;
}
head = head->next;
distanceFromHead++;
}
}
Your have two conditions:
finding the postion for insertion in the Linked list
not falling off the end of the Linked List
And, of course, you have to assign to *headRef, not to some local pointer variable. And you should not call malloc before you are absolutely sure you really need the memory.
You can combine the two conditions in a single loop:
void insert1(struct node **headRef, int index, int Data)
{
struct node *temp1;
int distanceFromHead = 0;
for( ; *head; head = &(*head)->next) {
if(distanceFromHead == index) break;
distanceFromHead++;
}
if (distanceFromHead != index) return; // index not found: list too short
temp1 = malloc(sizeof *temp1); //node to be inserted.
temp1->data = Data;
temp1->next = *head;
*head = temp1;
}
You dont need the distanceFromHeadvarable; you could just as well decrement the index:
void insert2(struct node **headRef, int index, int Data)
{
struct node *temp1;
for( ; *head; head = &(*head)->next) {
if(!index) break;
index--;
}
if (index) return; // index not found: list too short
temp1 = malloc(sizeof *temp1); //node to be inserted.
temp1->data = Data;
temp1->next = *head;
*head = temp1;
}
Now, the test for index!=0 is repeated after the loop. This can be avoided by moving the insertion inside the loop, and jumping out afterwards:
void insert3(struct node **headRef, int index, int Data)
{
for( ; *head; head = &(*head)->next) {
struct node *temp1;
if(index--) continue;
temp1 = malloc(sizeof *temp1); //node to be inserted.
temp1->data = Data;
temp1->next = *head;
*head = temp1;
break; // or : return;
}
return;
}
You're using head to iterate through the linked list and if index matched with distance then updating headref.
Problem is *headRef = head in while..if
And in if(index == 0) assign temp1 to *headref i.e. *headref=temp1

Resources