How to delete node from doubly linked list in c - c

I am working on doubly linked list in c, I have a doubly linked tepm2 with 20 nodes and I want to delete the node whose word user insert.
struct node {
struct node *prev;
char word[100];
int repeatTime;
struct node *next;
} *h, *temp, *temp1, *temp2;
Each node has unique word.
printf("\n Enter word to delete : ");
scanf("%s", &word);
Delete(word);
int delete(char data[200]) { //unable to delete
if (h == NULL)
return;
temp2 = next = previous = h;
while (temp2->next != NULL) {
if ((strcmp(temp2->word, data) == 0)) {
if (temp2->prev == NULL) {
h = temp2->next;
free(temp2);
return;
} else if (temp2->prev == NULL) {
previous->next = temp2;
free(temp2);
previous->next = NULL;
return;
} else {
previous->next = temp2->next;
next->prev = temp2->next;
}
}
temp2 = temp->next;
}
}
I am been unable to delete the specific node that word user enter

Try this:
int delete(const char *data)
{
struct node *temp = h;
if (h == NULL) return;
while (temp->next != NULL)
{
if (strcmp(temp->word, data) == 0)
{
if (temp->prev != NULL)
{
temp->prev->next = temp->next;
}
if (temp->next != NULL)
{
temp->next->prev = temp->prev;
}
if (h == temp)
{
h = temp->next;
}
free(temp);
return;
}
temp = temp->next;
}
}

First of all I don't think this is right temp2 = next = previous = h;
Now all you have to do is find the node that you want to delete by traversing and than link it's prev node to it's next node i.e. (temp2->prev)->next = next and (temp2->next)->prev = prev and free it.
Now the real issue lies with
1. The first node that has other nodes after it
2. last node that has other nodes preceding it
3. only node
You can simplify all three by converting them into the former problem i.e. node in the middle problem which we've just solved.
For simplifying you can just make the head and tail both NULL.

Related

Circular linked list crashes when displayed

I'm trying to make a circular linked list. When I try to display the list after creating it, the program keeps on crashing. Here is my code:
#include <stdio.h>
#include <stdlib.h>
typedef struct node {
int data;
struct node * next;
} node;
node * createList(int);
void display(node * head);
int main() {
struct node * head;
head = createList(5);
display(head);
}
node * createList(int n) {
int i = 0,data = 0;
struct node * head = NULL;
struct node * temp = NULL;
struct node * p = NULL;
for (i = 0; i < n; i++) {
temp = (node*)malloc(sizeof(node));
temp->data = data++;
temp->next = head;
if (head == NULL) {
head = temp;
} else {
p = head;
while (p->next != NULL) {
p = p->next;
}
p->next = temp;
}
}
return head;
}
void display(node * head) {
struct node * temp = head->next;
while (temp != head) {
printf("%d-> \t",temp->data);
temp = temp->next;
}
printf("\n");
}
What am I doing wrong?
You have set every temp's next to head in temp->next = head; but did it too early (the first is just NULL). Then you tested p->next against NULL in while (p->next != NULL) { but you should have tested against head. Alternatively, you can continue to test against NULL but then you need to initialize temp->next to NULL and assign head to temp->next only after the for loop.
Your display code started from the second link.
Here is a fixed code using the first option in 1. above:
for (i = 0; i < n; i++) {
temp = (node*)malloc(sizeof(node));
temp->data = data++;
if (head == NULL) {
head = temp;
} else {
p = head;
while (p->next != head) {
p = p->next;
}
p->next = temp;
}
temp->next = head;
}
Here is a fixed code using the alternative option in 1. above. You still need to initialize temp->next to NULL since malloc() does not initialize.
for (i = 0; i < n; i++) {
temp = (node*)malloc(sizeof(node));
temp->data = data++;
temp->next = NULL;
if (head == NULL) {
head = temp;
} else {
p = head;
while (p->next != NULL) {
p = p->next;
}
p->next = temp;
}
}
if (temp != NULL) {
temp->next = head;
}
But in reality, there is no need to "walk" from the head on every creation. You can simply keep the previous and link it to the next:
for (i = 0; i < n; i++) {
temp = (node*)malloc(sizeof(node));
temp->data = data++;
if (head == NULL) {
head = p = temp;
} else {
p = p->next = temp;
}
}
if (temp != NULL) {
temp->next = head;
}
Here is a fix for the display():
void display(node * head) {
struct node * temp = head;
if (temp != NULL) {
do {
printf("%d-> \t",temp->data);
temp = temp->next;
} while (temp != head);
}
printf("\n");
}
The problem is on the first node you initialize:
struct node *head = NULL;
...
for (i = 0; i < n; i++) {
...
temp->next = head;
So tmp->next == NULL on the first iteration leaving head->next == NULL. That will not work for a circular list. When you attempt to insert the 2nd node:
p = head;
while (p->next != NULL) {
What was head->next again?? (oh, NULL) Dereferencing a NULL pointer (BOOM Segfault!)
Do your circular list correctly. On insertion of the first node set:
if (head == NULL) {
head = temp;
head->next = temp; /* you must set head->next to temp */
} ...
So on the insertion of the remaining nodes you simply need:
} else {
p = head;
while (p->next != head) { /* iterate to last node */
p = p->next;
}
p->next = temp; /* now set p->next = temp */
}
Now, you handle your display() function the same way, e.g.
void display (node *head)
{
if (!head) { /* validate list not empty */
puts ("(list-empty)");
return;
}
struct node *temp = head;
do { /* same loop problem fixed in display() */
printf ("%d-> \t", temp->data);
temp = temp->next;
} while (temp != head);
putchar ('\n');
}
If you make the changes, then you can test your list with:
int main (void) {
struct node *head, *tmp;
head = createList(5);
display (head);
puts ("\niterate from mid-list");
tmp = head;
tmp = tmp->next;
tmp = tmp->next;
display (tmp);
}
Example Use/Output
$ ./bin/lls_circular_fix
0-> 1-> 2-> 3-> 4->
iterate from mid-list
2-> 3-> 4-> 0-> 1->
Lastly, you are not multiplying the type node by head in struct node * head = NULL; Write it as struct node *head = NULL; (the same for all your function declarations as well) Much more readable.
When you go to delete a note from the list, you must create a special case for both head and tail (the last node). In this sense, the singly-linked list takes a bit more effort than a doubly-linked list due to not having a prev node pointer to track the prior node.
Look things over and let me know if you have questions.
A full example would be:
#include <stdio.h>
#include <stdlib.h>
typedef struct node {
int data;
struct node *next;
} node;
node *createList (int);
void display (node *head);
int main (void) {
struct node *head, *tmp;
head = createList(5);
display (head);
puts ("\niterate from mid-list");
tmp = head;
tmp = tmp->next;
tmp = tmp->next;
display (tmp);
}
node *createList (int n)
{
int i = 0,data = 0;
struct node *head = NULL;
struct node *temp = NULL;
struct node *p = NULL;
for (i = 0; i < n; i++) {
if (!(temp = malloc (sizeof *temp))) {
perror ("malloc-temp");
return NULL;
}
temp->data = data++;
temp->next = head; /* head is NULL on 1st node insertion */
if (head == NULL) {
head = temp;
head->next = temp; /* you must set head->next to temp */
} else {
p = head;
while (p->next != head) { /* iterate to last node */
p = p->next;
}
p->next = temp; /* now set p->next = temp */
}
}
return head;
}
void display (node *head)
{
if (!head) { /* validate list not empty */
puts ("(list-empty)");
return;
}
struct node *temp = head;
do { /* same loop problem fixed in display() */
printf ("%d-> \t", temp->data);
temp = temp->next;
} while (temp != head);
putchar ('\n');
}

I am unable to display or insert correctly elements in singly circular linked list

I am unable to insert and display in singly circular linked list, It only inserts first elements and same with display function
void create() {
struct node *temp , *p;
temp = (struct node*)malloc(sizeof(struct node));
printf("Enter node data :");
scanf("%d",&(temp->data));
temp->next = NULL;
if(root == NULL) {
root = p = temp;
}
else {
while(p->next!=root) {
p->next = temp;
p = temp;
p->next = root;
}
}
}
void display() {
struct node *temp;
if(root == NULL) {
printf("List is Empty\n");
}
else {
temp = root;
while(temp->next!=root) {
printf("%d",temp->data);
temp = temp->next;
}
printf("%d",temp->next);
}
}
In this part of the create function:
while(p->next!=root) {
p->next = temp;
p = temp;
p->next = root;
}
variable p is not initialized, so p->next is an invalid dereference.
Changing it as follows:
p = root;
while(p->next!=root) {
p->next = temp;
p = temp;
p->next = root;
}
corrects the uninitialized variable. The code is still incorrect because it discards the existing elements on the list, so the list contains only the new element.
The following changes it to look for the last element of the list, and then appends the new element to the last element:
p = root;
while(p->next!=root) {
p = p->next;
}
p->next = temp;
Then it is necessary to link the new element (which is now the last element) to the first element to complete the circle:
temp->next = root;
For the case when the list is empty (i.e. root == NULL), after making root point to the new node (i.e. root = temp;), it is also necessary to make the new node point to itself, since it is also the first node:
temp->next = temp;
or:
temp->next = root;
The temp->next = root; statement can be moved to be after the if else statement since it is at the end of both branches.
Here is a slightly cleaned up version of the create function. I have not added any error checking for the result of the malloc and scanf call, since the main focus of the question and answer is to do with the circular linked list handling:
void create(void) {
struct node *temp , *p;
temp = (struct node*)malloc(sizeof(struct node));
printf("Enter node data :");
fflush(stdout);
scanf("%d",&(temp->data));
if(root == NULL) {
/* list is empty so new node will become both first and last node */
root = temp;
}
else {
/* find the current last node */
for (p = root; p->next != root; p = p->next)
;
/* append the new node so it will become last */
p->next = temp;
}
/* link the new, last node to the first node */
temp->next = root;
}
The existing display function should now work, but it can be simplified a bit with the use of a do while loop for the non-empty case:
void display(void) {
struct node *temp;
if(root == NULL) {
printf("List is Empty\n");
}
else {
temp = root;
do {
printf("%d ",temp->data);
temp = temp->next;
} while (temp!=root);
printf("\n");
}
}
It is not that much simpler, and still has two printf statements (although the last one could be changed to putchar('\n');). It also prints a space before the newline, so you may want to deal with the final element of the list separately after all:
void display(void) {
struct node *temp;
if(root == NULL) {
printf("List is Empty\n");
}
else {
for (temp = root; temp->next != root; temp = temp->next) {
printf("%d ",temp->data);
}
printf("%d\n", temp->data);
}
}

Why this destroy function throw Segmentation Fault in single linked list

I am new to Data Structures and C. this code work correctly in creating and inserting a node but when i call destroy function its case a Segmentation Fault.It seems to work correctly if i put all the code in the main function instead of other functions.
what cases this bug is :
• destroy
• delete IF deleted the head of the Linked List Only
can anyone please explain to me what is wrong with that?
#include <stdio.h>
#include <stdlib.h>
typedef struct node
{
int value;
struct node *next;
} node;
node *create_node(int value);
unsigned char insert(node *head, int value);
unsigned char delete_node(node *head, node *old_node);
node *search(node *head, int value);
unsigned char destroy(node *head);
int main(void)
{
node *head = create_node(1);
insert(head, 3);
insert(head, 2);
destroy(head);
for(node *i = head; i != NULL; i = i -> next)
{
printf("%i\n", i -> value);
}
}
// Will create a node and return it if succeeded else it will return NULL
node *create_node(int value)
{
node *new_node = malloc(sizeof(node));
// Check if the node created successfully or not
if (new_node == NULL)
{
return NULL;
}
new_node -> value = value;
new_node -> next = NULL;
return new_node;
}
// Insert the node to a list at the beginning of it, return 0 if succeed else number NOT 0
unsigned char insert(node *head, int value)
{
node *new_node = create_node(value);
// Check if the node created successfully or not
if (new_node == NULL)
{
return 1;
}
// Check if the List is exist or not
if (head == NULL)
{
return 2;
}
new_node -> next = head -> next;
head -> next = new_node;
return 0;
}
// Delete the node, return 0 if succeeded else number NOT 0
unsigned char delete_node(node *head, node *old_node)
{
// Check if the node is exist or not
if (old_node == NULL)
{
return 1;
}
node *back = head;
// If delete the first node ONLY
if (head == old_node)
{
free(old_node);
old_node = NULL;
return 0;
}
while (back -> next != old_node)
{
back = back -> next;
}
back -> next = old_node -> next;
free(old_node);
return 0;
}
// destroy the whole linked list, returns 0 if destroid successfully else number NOT 0
unsigned char destroy(node *head)
{
// Check if the List is exist or not
if (head == NULL)
{
return 1;
}
node *temp = head;
while (temp != NULL)
{
temp = temp -> next;
destroy(temp);
delete_node(head, temp);
}
delete_node(head, head);
return 0;
}
// return Pointer to node if founded it else return NULL
node *search(node *head, int value)
{
while (head != NULL)
{
// If founded it return it's pointer
if (head -> value == value)
{
return head;
}
else
{
head = head -> next;
}
}
return NULL;
}
I don't see exactly where the problem is here, but I do observe that your distroy (sic...) function is unnecessarily complicated. If your purpose is to destroy the entire list, you don't need to call a destroy_node routine. Just do something like this: (pseudocode ...)
while (head != NULL) {
temp = head->next;
free(head);
head = temp;
}
Your destroy_node routine also looks unnecessarily complicated. There are only two cases to consider: deleting the head node, and deleting a node that is not the head node. (pseudocode)
if (node == NULL) return;
if (node == head_node) {
head_node = head_node->next;
free(node);
} else {
temp = head_node;
while ((temp != NULL) {
if (temp->next == node) {
temp->next = temp->next->next; // link it out of the list
free(node);
return;
} else {
temp = temp->next;
}
}
}
your problem is here :
while (temp != NULL)
{
temp = temp -> next;
delete_node(head, temp);
}
your function delete_node(node *head, node *old_node) at the end execute:
free(old_node); // you free temp !
and you dont set old_node to NULL if your free this memory, your can't loop a second time here (because temp deleted):
while (temp != NULL)
{
temp = temp -> next;
delete_node(head, temp);
}

Why position 0 in delete node does not work?

Im new to c programming. I wanted to create a linked list from a given file and then randomly get a node from linked list then delete that node.
So the code works great but for the position 0 in linked list does not work.
Please help me
here's the code:
typedef struct node{
int *name;
struct node *next;
}node;
delete node:
void deleteNode(node **head_ref, int position){
if(*head_ref == NULL){
return;
}
node * temp = *head_ref;
if(position == 0)
{
*head_ref = (*head_ref)->next;
return;
}
int h;
for(h=0 ; temp!=NULL && h<position-1 ; h++){
temp = temp->next;
}
if(temp == NULL || temp->next == NULL)
return;
node * next = temp->next->next;
free(temp->next);
temp->next = next;}
getting random node:
void RandomFromList(node *head){
// IF list is empty
if (head == NULL){
return -1;
}
word = head->name;
// Iterate from the (k+1)th element to nth element
node *current = head;
int n;
for (n=2; current!=NULL; n++)
{
// change result with probability 1/n
if (rand() % n == 0)
word = current->name;
// Move to next node
current = current->next;
}
sprintf(words , "%s" , word);
deleteNode(&head , search(head , word));
printf("Randomly selected key is %s\n", words);}
and the file Reader:
node* fileReader(FILE *file){
node *t = malloc(sizeof(node));
char TopicName[20];
int fileRead = fscanf(file,"%s",TopicName);
if(fileRead != EOF){
t->name = strdup(TopicName);
tedad++;
t->next = fileReader(file);
}
if(fileRead == EOF) {
return NULL;
}
return t;}
EDIT:
When the code run's and when the position randomly got 0 the 0 position of linked list doesn't delete and continues with that node in linked list.
EDIT2:I changed my delete node and it works well without any problem, thank you guys!
node* deleteNode(node* head, unsigned i){
node* next;
if(head == NULL)
return head;
next = head->next;
return i == 0
? (free(head), next)
: (head->next = delete_at_index(next, i - 1), head);
}
The major logical problem I see with your delete function is that it is void, i.e. it returns nothing. This is fine if the node being deleted is in the middle (or end) of the list, because the head does not change. But for the case of deleting the head, the caller might expect that his reference would then point to the next node (or null, if a list of one element) after making the call. Consider this code:
node* deleteNode (node *head_ref, int position)
{
// passing in a NULL list returns NULL
if (head_ref == NULL) {
{
return NULL;
}
// deleting the first element returns the second element as the new head
node* temp = head_ref;
if (position == 0)
{
node* ret = temp->next;
free(head_ref);
return ret;
}
// otherwise walk down the list to one before the deletion position
for (int h=0; temp != NULL && h < position-1; h++) {
temp = temp->next;
}
// if found, delete the node at the desired position
if (temp != NULL && temp->next == NULL) {
node* next = temp->next->next;
free(temp->next);
temp->next = next;
}
// for cases other than deleting the head, just return the current
// (unmodified) head
return head_ref;
}
This isn't related to your problem, but don't forget to free the memory:
node * temp = *head_ref;
if(position == 0)
{
*head_ref = temp->next;
free(temp); // <--------
return;
}
Also, you already have a pointer (temp) to *head_ref, it looks cleaner to me to just use that pointer instead of dereferencing head_ref again.
void deleteNode(node **head_ref, int pos){
node *del;
for ( ; *head_ref; head_ref = &(*head_ref)->next) {
if (pos-- <= 0) break;
}
if (!*head_ref) return; // Reached end of list: nothing found
del = *head_ref;
*head_ref = del->next;
free(del);
return;
}
If you want to keep deleteNode void, then the problem is with your RandomFromList function. You are just changing the * head that exists in the function body not the pointer you passed to the function, so it's still pointing to the previous node.
It's because that pointers are passed by value (copied) like other things in C.
Try making RandomFromList return the head pointer.
P.s. I think you also have some memory leaks in the delete function.

C - Inserting into linked list in ascending order

I am trying to create a program that inserts numbers into a linked list in ascending order. This is my insert function. It works for inserting some numbers but not others. I think it has something to do with the last part, but i cant figure it out.
node* insert(node* head, int value) {
//check if head hasn't been created
if (head == NULL) {
head = malloc(sizeof(node));
if(head == NULL) {
printf("Failed to create head node");
return head;
}
head->value = value;
head->next = NULL;
return head;
}
//create a new node
node *newNode;
newNode = malloc(sizeof(node));
if(newNode == NULL) {
printf("Failed to create node");
return newNode;
}
newNode->value = value;
newNode->next = NULL;
//see if new node should be placed before head
if (value < head->value) {
newNode->next = head;
return newNode;
}
//search through to find correct spot and insert the node
node *temp = NULL;
temp = head;
while(temp->next != NULL && temp->value < value) {
temp = temp->next;
}
newNode->next = temp->next;
temp->next = newNode;
return head;
}
Part of the following bad
//search through to find correct spot and insert the node
node *temp = NULL;
temp = head;
while(temp->next != NULL && temp->value < value) {
temp = temp->next;
}
newNode->next = temp->next;
temp->next = newNode;
e.g. to fix like this:
node *temp ,*prev;
temp = head;
while(temp != NULL && temp->value <= value) {
prev = temp;
temp = temp->next;
}
newNode->next = temp;
prev->next = newNode;
or
node *temp ,*prev;
temp = head->next;
prev = head;
while(temp != NULL && temp->value < value) {
prev = temp;
temp = temp->next;
}
newNode->next = temp;
prev->next = newNode;
You need to check for temp->next->value inside the last while loop.
//This code of mine works perfectly.
void insertInAscOrder(int val)
{
node *new1;
node *temp;
node *previous;
//create new node
new1 = (node *)malloc(sizeof(node));
//check whether node is created or not
if(new1 == NULL)
{
printf("Insufficient memory.");
return;
}
//Updating different parts of the node
new1 -> info = val;
new1 -> next = NULL;
//checking whether the node created is only node or not
if (start == NULL)
{
start = new1;
}
//If value is less than the value of first node
else if(val < start -> info)
{
new1 -> next = start;
start = new1;
}
else
{
previous = start;
temp = start -> next;
//Go to the position where node is to be inserted
while(temp != NULL && val > temp -> info)
{
previous = temp;
temp = temp -> next;
}
//Insert the node at particular position
if(temp == NULL)
{
previous -> next = new1;
}
else
{
new1 -> next = temp;
previous -> next = new1;
}
}
}
It would be much better if you firstly implement (and test) functions like: push_front(), insert() (insert before), and push_back(), (probably advance (Node* curr, int steps);) and then simply take into consideration all the possibilities of insertion, i.e.:
empty list (current node is first, so just push_front / back())
iterate (advance()) over all elements from head and on, till:
element with value larger than the new is found, insert() before it.
last element reached, push_back().
in your new function insert_ordered().

Resources