insert element at nth position in the linked list - C - 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

Related

Element deletion in single linked list at head not working

#include <stdio.h>
#include <stdlib.h>
struct node {
int data;
struct node *next;
};
struct node *head = NULL;
struct node *second = NULL;
struct node *third = NULL;
void insertAtBeg(struct node *n, int data) {
struct node *temp;
temp = (struct node *)malloc(sizeof(struct node));
temp->data = data;
temp->next = head;
head = temp;
}
void insertAtEnd(struct node *n, int data) {
struct node *temp;
temp = (struct node*)malloc(sizeof(struct node));
temp->data = data;
temp->next = NULL;
while (n->next != NULL) {
n = n->next;
}
n->next = temp;
}
void deleteElement(struct node *head, int data) {
if (head->data == data) {
struct node *temp;
temp = head;
head = head->next;
free(temp);
printf("after deletion at head in function\n");
printList(head);
}
}
void printList(struct node *n) {
while (n != NULL) {
printf("%d\n", n->data);
n = n->next;
}
}
void main() {
head = (struct node*)malloc(sizeof(struct node));
second = (struct node*)malloc(sizeof(struct node));
third = (struct node*)malloc(sizeof(struct node));
head->data = 1;
head->next = second;
second->data = 2;
second->next = third;
third->data = 3;
third->next = NULL;
printList(head);
insertAtBeg(head, 0);
printf("after insertion at beginning\n");
printList(head);
insertAtEnd(head, 4);
printf("after insertion at End\n");
printList(head);
deleteElement(head, 0);
printf("after deletion at head in main\n");
printList(head);
}
output of the code is
1
2
3
after insertion at beginning
0
1
2
3
after insertion at End
0
1
2
3
4
after deletion at head in function
1
2
3
4
after deletion at head in main
0
1
2
3
4
Why is there a difference in output of the function called in main and the function called in another function.ie.after deletion at head in function and after deletion at head in main, when both are supposed to be deleting element from the same list
The problem is you need a way to modify the head of the list when inserting and/or deleting elements from the list.
A simple way to do this is for these functions to return a potentially updated value of the head pointer and for the caller to store this return value into it's head variable.
Here is a modified version of your code with these semantics:
#include <stdio.h>
#include <stdlib.h>
struct node {
int data;
struct node *next;
};
struct node *insertAtBeg(struct node *head, int data) {
struct node *temp;
temp = (struct node *)malloc(sizeof(struct node));
// should test for memory allocation failure
temp->data = data;
temp->next = head;
return temp;
}
struct node *insertAtEnd(struct node *head, int data) {
struct node *temp;
struct node *n;
temp = (struct node*)malloc(sizeof(struct node));
// should test for memory allocation failure
temp->data = data;
temp->next = NULL;
if (head == NULL)
return temp;
n = head;
while (n->next != NULL) {
n = n->next;
}
n->next = temp;
return head;
}
struct node *deleteElement(struct node *head, int data) {
// delete the first node with a given data
if (head->data == data) {
struct node *temp = head;
head = head->next;
free(temp);
} else {
struct node *n = head;
while (n->next != NULL) {
if (n->next->data == data) {
struct node *temp = n->next;
n->next = temp->next;
free(temp);
break;
}
}
}
return head;
}
void printList(const struct node *n) {
while (n != NULL) {
printf("%d\n", n->data);
n = n->next;
}
}
int main() {
struct node *head = NULL;
head = insertAtBeg(head, 1);
head = insertAtEnd(head, 2);
head = insertAtEnd(head, 3);
printList(head);
head = insertAtBeg(head, 0);
printf("after insertion at beginning\n");
printList(head);
head = insertAtEnd(head, 4);
printf("after insertion at End\n");
printList(head);
head = deleteElement(head, 0);
printf("after deletion at head in main\n");
printList(head);
// should free the list
return 0;
}
An alternative is to pass the address of the list head pointer so the function can modify it if needed.
Here is a modified version of your code with this alternative approach:
#include <stdio.h>
#include <stdlib.h>
struct node {
int data;
struct node *next;
};
struct node *insertAtBeg(struct node **headp, int data) {
struct node *temp = malloc(sizeof(*temp));
if (temp != NULL) {
temp->data = data;
temp->next = *headp;
*headp = temp;
}
return temp;
}
struct node *insertAtEnd(struct node **headp, int data) {
struct node *temp = malloc(sizeof(*temp));
if (temp != NULL) {
temp->data = data;
temp->next = NULL;
if (*headp == NULL) {
*headp = temp;
} else {
struct node *n = *headp;
while (n->next != NULL) {
n = n->next;
}
n->next = temp;
}
}
return temp;
}
int deleteElement(struct node **headp, int data) {
// delete the first node with a given data
struct node *head = *headp;
if (head->data == data) {
*headp = head->next;
free(temp);
return 1; // node was found and freed
} else {
struct node *n = head;
while (n->next != NULL) {
if (n->next->data == data) {
struct node *temp = n->next;
n->next = temp->next;
free(temp);
return 1; // node was found and freed
}
}
return 0; // node not found
}
}
void printList(const struct node *n) {
while (n != NULL) {
printf("%d\n", n->data);
n = n->next;
}
}
int main() {
struct node *head = NULL;
insertAtBeg(&head, 1);
insertAtEnd(&head, 2);
insertAtEnd(&head, 3);
printList(head);
insertAtBeg(&head, 0);
printf("after insertion at beginning\n");
printList(head);
insertAtEnd(&head, 4);
printf("after insertion at End\n");
printList(head);
deleteElement(&head, 0);
printf("after deletion at head in main\n");
printList(head);
// free the list
while (head != NULL) {
deleteElement(&head, head->data);
}
return 0;
}
This alternative approach uses double pointers, so it is a bit more difficult for beginners to comprehend, but it has a strong advantage: the functions can update the list pointer and provide a meaningful return value that can be tested to detect errors. For example insertAtBeg() and insertAtEnd() return NULL if the new node could not be allocated but preserve the list. Similarly deleteElement() can return an indicator showing whether the element was found or not.
With this approach, you can write functions to pop the first or last element of the list, or the one at a given index, or one with a given data, while updating the list pointer as needed.
In the function void deleteElement(struct node *head,int data) you are passing a pointer to the head node. If you make changes to the node, then that works because you are pointing to the actual node. However, the variable head is a local copy of the pointer, which is not the one in main. When you change head to head->next that is only changing the local copy, so it has no effect outside deleteElement.
ADVANCED LEVEL POINTERS
To actually change head you have to pass a pointer to it, making a double pointer:
void deleteElement(struct node **phead,int data) {
struct node *temp;
temp = *phead;
*phead = (*phead)->next;
this means you have to pass the address of head &head as the parameter.

Deleting a node at a given position in Linked List

Given a singly linked list and a position, i am trying to delete a linked list node at a specific position.
CODE:
#include<stdio.h>
#include<stdlib.h>
struct node
{
int data;
struct node* next;
};
void printList(struct node* head_ref)
{
//struct node* head_ref = (struct node*)malloc(sizeof(struct node));
if(head_ref == NULL)
printf("The list is empty");
while(head_ref!=NULL)
{
printf("%d\n",head_ref->data);
head_ref = head_ref->next;
}
}
void insert_beg(struct node **head_ref,int new_data)
{
struct node* new_node = (struct node*)malloc(sizeof(struct node));
new_node->data = new_data;
new_node->next = *head_ref;
*head_ref = new_node;
}
void delete(struct node **head_ref,int position)
{
int i=1;
if(*head_ref == NULL)
return;
struct node *tails,*temp = *head_ref;
if(position == 0)
{
*head_ref = temp->next;
free(temp);
return;
}
while(temp->next!=NULL)
{
tails = temp->next;
temp = temp->next;
if(i == position)
{
tails->next = temp->next;
free(temp);
return;
}
i++;
}
}
int main()
{
struct node *head = NULL;
insert_beg(&head,36);
insert_beg(&head,35);
insert_beg(&head,34);
insert_beg(&head,33);
printList(head);
int position;
printf("Enter the position of the node u wanna delete\n");
scanf("%d",&position);
delete(&head,position);
printf("\n");
printList(head);
}
Whenever I am trying to delete a node above position 0, I am getting 0 in that specific position instead of nothing. Could I know where I am going wrong?
For eg my list is : 33 34 35 36
My Output: 33 0 35 36 (while attempting to delete node 1)
Valid Output: 33 35 36
The problem occurs due to this wrong statement
while(temp->next!=NULL)
{
tails = temp->next;
^^^^^^^^^^^^^^^^^^^
temp = temp->next;
In this case tails and temp are the same nodes. And if temp is deleted then you set the data member next of the deleted node to temp->next
if(i == position)
{
tails->next = temp->next;
^^^^^^^^^^^^^^^^^^^^^^^^^
Here tails is node that will be deleted.
You should change the data member next of the node before the deleted node. So the wrong statement should be updated like
while(temp->next!=NULL)
{
tails = temp;
^^^^^^^^^^^^^
temp = temp->next;
As for me then I would write the function the following way
int delete( struct node **head, size_t position )
{
struct node *prev = NULL;
size_t i = 0;
while ( i != position && *head != NULL )
{
prev = *head;
head = &( *head )->next;
++i;
}
int success = *head != NULL;
if ( success )
{
struct node *tmp = *head;
if ( prev == NULL )
{
*head = ( *head )->next;
}
else
{
prev->next = ( *head )->next;
}
free( tmp );
}
return success;
}
Into your delete function while loop tails and temp move forward a the same time starting fro the same address. The node is not deleted because you are always assigning the same value (in other words you are only confirm next pointer value each time).
That means that, after your cancellation, printout is UB due to the freed memory of one of the nodes.
Correcting your code:
void delete(struct node **head_ref,int position)
{
int i=1;
if(*head_ref == NULL)
return;
struct node *temp = *head_ref;
if(position == 0)
{
*head_ref = temp->next;
free(temp);
return;
}
struct node *tails = *head_ref;
while(temp->next!=NULL)
{
temp = temp->next;
if(i == position)
{
tails->next = temp->next;
free(temp);
return;
}
tails = tails->next;
i++;
}
}

Implementing Simple Linked List

Hi I wish to implement a simple linked list and all the values to the end of the list. As simple as that but I am not able to do so. Can you please tell me where I am doing it wrong ? Initially I am declaring a pointer and assigning NULL value to it. Later in each iteration I am allocating memory to the pointer that was initially NULL.
#include <stdio.h>
#include <malloc.h>
struct node{
int a;
struct node* next;
};
struct node* insert(struct node* start,int value);
void print(struct node* head);
int main()
{
int a;
struct node* head = NULL;
while(scanf("%d",&a) != EOF)//taking input
{
head = insert(head,a);
print(head);
}
return 0;
}
struct node* insert(struct node* start,int value)
{
struct node* head = start;
while(start != NULL)
{
start = start->next;//getting upto the end of the linked list
}
start = (struct node*)malloc(sizeof(struct node));//allocating memory at the end
start->a = value;
start->next = NULL;
if(head == NULL)
{
return start;//for the base case when list is initally empty
}
return head;
}
void print(struct node* head)
{
while(head != NULL)
{
printf("%d\n",head->a);
head = head->next;
}
return;
}
You're losing your linkage between your tail and your new node, try this instead
struct node* insert(struct node* head,int value)
{
struct node* tail = head;
while(tail != NULL && tail->next != NULL)
{
tail= tail->next;//getting upto the end of the linked list
}
struct node* start = (struct node*)malloc(sizeof(struct node));//allocating memory at the end
start->a = value;
start->next = NULL;
if(head == NULL)
{
return start;//for the base case when list is initally empty
}
else
{
tail->next = start;
}
return head;
}
struct node* insert(struct node* start,int value){
struct node* head = start;
struct node* np = (struct node*)malloc(sizeof(struct node));
np->a = value;
np->next = NULL;
if(head == NULL)
return np;
while(start->next != NULL){
start = start->next;
}
start->next = np;
return head;
}
What makes the approach I am using buggy ?
nodeX
|
+a
|
+next(address to OtherX)
nodeX.next = new_node;//update link(case of OK)
tempPointer = nodeX.next;//address to OtherX set to tempPointer
tempPointer = new_node;//contents of tempPointer changed, but orignal (nodeX.next not change)

Doubly Linked List Pointer Confusion

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.

Why does one element stays in original list when selection sorting?

#include <stdio.h>
#include <stdlib.h>
struct node {
int val;
struct node* next;
} ;
struct node* largest(struct node** first)
{
struct node* largest = *first;
struct node* prev = NULL;
struct node* temp_prev = NULL;
for(;first != NULL; first = first -> next)
{
if (first -> val > largest -> val)
{
largest = first;
prev = temp_prev;
}
temp_prev = first;
}
if(prev != NULL)
prev -> next = largest -> next;
largest -> next = NULL;
return largest;
}
struct node* sel_sort(struct node** list)
{
struct node* head = NULL;
struct node* temp_largest = NULL;
while (*list)
{
head = largest(list);
head->next=temp_largest;
temp_largest = head;
}
*list = head; // note sets the input pointer to the new list.
return head;
}
void print_list(struct node* first)
{
struct node* temp;
for (temp = first; temp != NULL; temp = temp->next)
{
printf("%d\n", temp->val);
}
}
void main() {
struct node* r = malloc(sizeof(struct node));
struct node* s = malloc(sizeof(struct node));
struct node* t = malloc(sizeof(struct node));
struct node* w = malloc(sizeof(struct node));
struct node* q = malloc(sizeof(struct node));
r->val = 2;
r->next = s;
s->val = 10;
s->next = t;
t->next = w;
t->val = 3;
w->val = 1;
w->next = q;
q->val = 6;
q->next = NULL;
printf("\nBefore Sort:\n");
print_list(r);
printf("\nSorted:\n");
struct node* sorted = sel_sort(&r);
print_list(sorted);
}
In short, the above is selection sort for a singly linked list. I'm having an issue where an infinite loops occurs in the sel_sort method, because no matter how many times I call the largest method, one node will be left in the original list. Other then that my code seems to work, but how do I get around this small problem?
So, what do you expect will ever modify the variable list in this while-loop:
struct node* temp = *list;
struct node* head;
struct node* temp_largest = NULL;
while (list != NULL) // <<=== infinite loop
{
head = largest(temp);
head->next=temp_largest;
temp_largest = head;
}
return head;
I question your use of temp. Technically your largest() function should take a list head by address (pointer to pointer), extract the largest node, returning that node after removal from the list, and updating the passed-in list head on the off-chance it was the first node in the list (therefore the head has to be moved):
struct node* head = NULL;
struct node* temp_largest = NULL;
while (*list)
{
head = largest(list);
head->next=temp_largest;
temp_largest = head;
}
*list = head; // note sets the input pointer to the new list.
return head;
And have largest() take a list pointer by address (a double pointer)
struct node* largest(struct node** first)
{
struct node *prev = NULL;
struct node *lprev = NULL;
struct node *cur = NULL;
struct node *largest = NULL;
if (!(first && *first))
return NULL;
// assume the first node is the largest node
largest = lprev = prev = *first;
cur = largest->next;
for(; cur; prev = cur, cur = cur->next)
{
if (cur->val > largest->val)
{
largest = cur;
lprev = prev;
}
}
// go with the simple stuff first. was `largest`
// the first item in the list?
if (largest == *first)
{
// yes it was, so move the list head.
*first = largest->next;
}
else
{ // no it was not, so link `lprev` to be
// the node following `largest`
lprev->next = largest->next;
}
// regardless. always unlink the largest node.
largest->next = NULL;
return largest;
}
Using this in combination with the updated sort, I get this for output:
Output
Before Sort:
2
10
3
1
6
Sorted:
1
2
3
6
10

Resources