Merge sort is often preferred for sorting a linked list. The slow random-access performance of a linked list makes some other algorithms (such as quicksort) perform poorly, and others (such as heapsort) completely impossible.
I have been struggling to do Merge Sort on a linked list. It keeps throwing back an error. I'm providing the code I've tried to execute. Please do help me out.
It keeps giving runtime error.
#include <stdio.h>
#include <stdlib.h>
struct node {
int data;
struct node *next;
};
struct node *SortedMerge(struct node *a, struct node *b);
void FrontBackSplit(struct node *source, struct node *frontref, struct node *backref);
struct node *Create(struct node *head, int num) {
struct node *newnode, *temp;
newnode = (struct node *)malloc(sizeof(struct node));
newnode->data = num;
newnode->next = NULL;
if (head == NULL) {
head = newnode;
temp = newnode;
} else {
temp->next = newnode;
temp = temp->next;
}
temp->next = NULL;
return head;
}
struct node *display(struct node *head) {
struct node *temp;
temp = head;
while (temp != NULL) {
printf("%d->", temp->data);
temp = temp->next;
}
printf("NULL");
return head;
}
struct node *MergeSort(struct node *head) {
struct node *headref, *a, *b;
headref = head;
if ((head == NULL) || (head->next) == NULL) {
return;
}
FrontBackSplit(headref, a, b);
MergeSort(a);
MergeSort(b);
head = SortedMerge(a, b);
return head;
}
void FrontBackSplit(struct node *source, struct node *frontref, struct node *backref) {
struct node *fast, *slow;
slow = source;
fast = source->next;
while (fast != NULL) {
fast = fast->next;
if (fast != NULL) {
slow = slow->next;
fast = fast->next;
}
}
frontref = source;
backref = slow->next;
slow->next = NULL;
}
struct node *SortedMerge(struct node *a, struct node *b) {
struct node *result;
result = NULL;
if (a == NULL) {
return (b);
}
else if (b == NULL) {
return (a);
}
if (a->data <= b->data) {
result = a;
result->next = SortedMerge(a->next, b);
} else {
result = b;
result->next = SortedMerge(a, b->next);
}
return result;
}
int main() {
struct node *head = NULL;
int i, n, num;
scanf("%d", &n);
for (i = 0; i < n; i++) {
scanf("%d", &num);
head = Create(head, num);
}
head = MergeSort(head);
display(head);
}
There are a couple of problems with the code, and which one triggers the error you are seeing I cannot say, but I will point out a few of them below. Take Create():
struct node *Create(struct node *head, int num)
{
struct node *newnode, *temp;
newnode=(struct node *)malloc(sizeof(struct node));
newnode->data=num;
newnode->next=NULL;
if(head==NULL) {
head=newnode;
temp=newnode;
} else {
temp->next=newnode;
temp=temp->next;
}
temp->next=NULL;
return head;
}
I cannot work out exactly what it is supposed to do, to be honest. Maybe add a new node to a list, represented by a head link? It doesn't do that. You create a new node
newnode=(struct node *)malloc(sizeof(struct node));
which I would suggest you write as
newnode = malloc(sizeof *newnode);
You don't need to cast void *, so you don't need to cast the result of malloc(), and using sizeof *newnode rather than sizeof(struct node) is safer. But the code works correctly in the form you have, so there is not a problem there. However, what happens with that node depends on head. If head is NULL, you point it at the new node, and through temp you (re)assign the new node's next to NULL. So now you will return an updated head that consists of the new node as a single element list. That matches my guess at what the function should do.
However, if head is not NULL, you put the new node in temp->next, which is a problem, since temp isn't initialised. You write to temp in the if(head==NULL) branch, but you dereference it in the else branch, where it can point anywhere. I am surprised if you don't get a segmentation fault from time to time here. It isn't necessary to assign the new node to temp->next, though, because immediately afterwards you change temp to point to temp->next, which is where you just put newnode, so temp = newnode would do the trick, without the segfault. But not all is well if we do that. We now would have the new node in temp (with the next pointer, again, reassigned to NULL) and then we return head. We didn't connect head with newnode anywhere, if we took the else branch. So calling Create() with a non-NULL head creates a new node, throws it away (and leaking memory), and that is all that does.
So while my guess is that Create() should add a new to a list, represented by head, or something to that effect, what it actually does is create a single-element list if the first argument is NULL, and leak sizeof(struct node) memory while doing nothing if head != NULL.
That being said, the code might work by pure luck of course. When I tried it with clang with zero optimisation, I somehow managed to build a list correctly. This is luck, though. It won't work in general. I suspect that what happens is that the repeated calls to Create() in the loop in main() happens to leave the last node you created (and wrote to temp) at the same stack location as the uninitialised temp in the next call. So by pure luck, putting the new node in temp's next appends the new node to the last node you created. It was really interesting working that one out :) But don't rely on this, of course. It is a combination of several lucky circumstances. Add optimisation flags, and the compiler will change the stack layout, and the code will break. Call other functions between successive calls to Create() and the stack will change, and then you don't have the last link on the stack any longer. And the code will break. It is a very unstable situation if this works at all.
If you just want to add a new node to a list, make a prepend function. Something like
struct node *prepend(int val, struct node *list)
{
struct node *n = malloc(sizeof *n);
if (n) {
n->data = val;
n->next = list;
}
return n;
}
(I haven't tested it, so there might by syntax errors, but it will be something like that...you need to figure out what to do if malloc() fails, but you could just abort() if you don't want to deal with it).
There is nothing wrong with display(), except that I don't understand why it is in lower-case when the other functions are in camel-case. You don't need temp, you can use head in the while-loop, but that is a style choice. The function works as intended.
With MergeSort(), however, we have another problem. I am surprised that your compiler didn't scream warnings at you here. It should really give you an error, with the right flags, but at the very least an error. When you test if the list is empty or a singleton, you return, but not with a node. The function should return a struct node *, so just using return will not give you anything useful.
if((head==NULL) || (head->next)==NULL){
return;
}
If the base case of the recursion returns garbage, obviously the whole recursion tumbles. Otherwise, assuming that the FrontBackSplit() and SortedMerge() work, the function looks okay. You don't need the extra headref variable, it is just a synonym for head, but there is nothing wrong with having it. The compiler will get rid of it for you. There isn't any need to assign the merged lists to head and then return head either. You can just return SortedMerge(a,b). But again, your compiler will handle that for you, once you turn on optimisation. Except for the base case, I believe the function should work.
In FrontBackSplit(), I get the impression that you want to get the frontref and backref values back to the caller. Otherwise, the function doesn't do anything. But when you are modifying the function parameters, you are not changing the variables in the caller's scope. You need to pass the two pointers by reference, which means that you need to use pointers to pointers. Change it to something like this:
void FrontBackSplit(struct node *source,
struct node **frontref,
struct node **backref)
{
struct node *fast, *slow;
slow=source;
fast=source->next;
while(fast!=NULL) {
fast=fast->next;
if(fast!=NULL) {
slow=slow->next;
fast=fast->next;
}
}
*frontref=source;
*backref=slow->next;
slow->next=NULL;
}
When you call the function, use the addresses of the parameters for the second and third argument, so use FrontBackSplit(headref,&a,&b); instead of FrontBackSplit(headref,a,b);.
As far as I can see, SortedMerge() should work (with a modified FrontBackSplit()). It is recursive, but not tail-recursive, so you might have problems with overflowing the stack for long lists. It isn't hard to make iterative, though.
You should make main() either int main(void) or int main(int, char**). You should return 0 for success.
My guess is that one of three things are breaking your code. When you Create() your lists, you do not get the lists you want. In just the right circumstances, with just the right compiler and function call configurations, however, you might get lucky (and maybe that is what you have seen). In that case, it might be the return in MergeSort(). Return head instead, there, that is probably what you want. If you have an empty list or a list of length one, you should return that list. So change return; to return head;. And if it isn't that either, it is probably because you recurse on random data in MergeSort(), because a and b aren't initialised in the recursion. They are uninitialised when you call FrontBackSplit() and the call doesn't change them, because they are passed by value and not reference. The change I listed above will fix that.
There might be more that I have overlooked, but at least those three issues are enough to break the code, each of them on their own, so it is a good place to start with debugging.
Related
There are many implementations available on the net, but I wanted to do it on my own.
Can anyone tell what mistakes I am making?
When I created the linked list, I gave input as 3,12,5,2. So after sorting it should have been 2,3,5,12, but it gave me output as 3,5,2,12.
#include <stdio.h>
#include <stdlib.h>
struct node
{
int data;
struct node *next;
};
struct node *start=NULL;
void sort()
{
struct node *preptr, *ptr, *temp;
temp = (struct node *)malloc(sizeof(struct node));
ptr=start;
while(ptr->next != NULL)
{
preptr=ptr;
ptr=ptr->next;
if (preptr->data > ptr->data )
{
temp->data=ptr->data;
ptr->data=preptr->data;
preptr->data=temp->data;
ptr=start;
}
}
}
You appear to have attempted to implement Bubble Sort, but that requires multiple passes through the data in the general, and you perform only one. On that one pass, with input 3, 12, 5, 2, your code
compares 3 with 12, and makes no change;
compares 12 with 5, and swaps them;
compares 12 with 2, and swaps them.
Then it stops, leaving 3, 5, 2, 12 as the final result.
A Bubble Sort on an n-element list must make n - 1 passes through the list in the general case, and your particular input happens to require that maximum number of passes. One way to fix it would be to just run your existing code for one sorting pass inside a for loop that runs n - 1 times, but of course you then need to compute n first. A better way (without changing to an altogether better algorithm) would be to run an indeterminate number of passes, via an outer loop, keeping track of whether any swaps are performed during the pass. You're then done when you complete a pass without making any swaps.
Additional notes:
You don't need a struct node just to swap the int data of two nodes.
If want a struct node for a local temporary, you don't need to allocate it dynamically. Just declare it:
struct node temp_node;
If you want a struct node * for a local temporary, you (probably) do not need to allocate any memory for it to point to.
If you want a struct node for a local temporary and a pointer to it, you still don't need to allocate anything dynamically. Just declare the struct and take its address:
struct node temp_node;
struct node *temp = &temp_node;
The main reasons to allocate dynamically are that you don't know in advance how much memory you will need, or that the allocated object needs to outlive the execution of the function in which it is created.
Sorting a linked list is usually accomplished by rearranging the nodes by changing their links, not by swapping the node payloads, as your function does. It's not necessarily wrong to swap the payloads, but that does not take any advantage of the linked list structure.
As you wrote in comments that you actually need to move the nodes, not the values, you will need to reassign the next pointers.
For the same reason, it must be possible for start to reference a different node. Therefore I would suggest that sort takes start as an argument and returns the new value it.
For implementing bubble sort, you need an extra outer loop, which restarts the iteration over the list. This should be repeated at most n times, where n is the number of nodes in your list. You could also just check whether a swap was necessary and in that case decide to do another scan through your list... until no more swaps occur.
I have here implemented that second idea:
#include <stdio.h>
#include <stdlib.h>
struct node {
int data;
struct node *next;
};
// A function to create a new node.
// This allows for easy initialisation of a linked list
struct node *newNode(int data, struct node *next) {
struct node *temp = (struct node *)malloc(sizeof(struct node));
temp->data = data;
temp->next = next;
return temp;
}
// Useful to see what is in the list...
void printList(struct node *cur) {
while (cur != NULL) {
printf("%i ", cur->data);
cur = cur->next;
}
printf("\n");
}
// Let the sort function
struct node * sort(struct node *start) {
struct node *prev, *cur, *next;
// flag indicating we are not sure yet that
// the list is sorted
int mutation = 1;
// extra dummy node that precedes the start node
struct node sentinel;
sentinel.next = start;
while (mutation) {
mutation = 0;
prev = &sentinel;
cur = sentinel.next;
next = start->next;
while (next != NULL) {
if (cur->data > next->data ) {
// swap cur and next
prev->next = next;
cur->next = next->next;
next->next = cur;
// flag that we need more iterations
mutation = 1;
// prepare for next iteration
prev = next;
} else {
prev = cur;
cur = next;
}
next = cur->next;
}
}
return sentinel.next;
}
// demo:
int main(void) {
// Create list that was given as example
struct node *start = newNode(3, newNode(12, newNode(5, newNode(2, NULL))));
printf("Input:\n");
printList(start);
start = sort(start);
printf("Sorted:\n");
printList(start);
return 0;
}
It looks there is no duplicate questions...so i want a function to free all nodes in a single linked list, and i want to do it recursively. I come up with a close one that i thought it would work, but it does not. It seems that after it removed one node, the upper stack function will not excuse, recursively. I am wondering how to modify the code to make it work.
#include <stdlib.h>
#include<stdio.h>
#include<stdlib.h>
struct Node
{
int data;
struct Node *next;
};
void ft_list_clear(struct Node *begin_list)
{
if ((begin_list->next))
ft_list_clear(begin_list->next);
if(!(begin_list->next))
{
free(begin_list);
begin_list = NULL;
}
}
int main()
{
struct Node* head = NULL;
struct Node* second = NULL;
struct Node* third = NULL;
// allocate 3 nodes in the heap
head = (struct Node*)malloc(sizeof(struct Node));
second = (struct Node*)malloc(sizeof(struct Node));
third = (struct Node*)malloc(sizeof(struct Node));
head->data = 1; //assign data in first node
head->next = second; // Link first node with second
second->data = 2; //assign data to second node
second->next = third;
third->data = 3; //assign data to third node
third->next = NULL;
ft_list_clear(head);
return 0;
}
You're pretty close
void ft_list_clear(struct Nude *list)
{
if (!list) { return; }
ft_list_clear(list->next);
list->next = null;
free(list);
}
Explaining the code
The first if checks if the list is currently null and exits the recursion if so.
If the list isn't null recursively call the function.
This repeats until the end of the list null.
Then since the next has been cleared by the recursive call you can set it to null in this call (not strictly necessary since this clears everything).
Finally actually free this node prior to returning to the previous call (this node's parent).
You can also do the delete in the opposite order if you want
void ft_list_clear(string Node *list)
{
if (!list) { return; }
struct Node *next = list->next;
free(list);
ft_list_clear(next);
}
Same principles just deletes this node before going to the next. This means you don't need to fix the next pointers but you will need to copy them first so you don't lose the reference.
I think it's because you're just freeing nodes, but you miss to nullify the next members. Try this. I haven't run this so goodluck.
void ft_list_clear(struct Node *begin_list)
{
if ((begin_list->next))
{
ft_list_clear(begin_list->next);
begin_list->next = NULL; // <-- you should nullify the next of the current after you free the node which it points to.
}
if(!(begin_list->next)) // <-- even if the next node was deleted, this won't run if you didn't nullify begin_list->next
{
free(begin_list);
begin_list = NULL;
}
}
`void ft_list_clear(struct Node *begin_list)
{
if ((begin_list->next))
ft_list_clear(begin_list->next);
free(begin_list);
begin_list = NULL;
printf("God bless America");
}`
Hopefully, if God blesses America thrice, your code is working, I've committed some changes in your code, and all I did was remove the second if statement because usually, we don't need that in recursion (I'm not saying we don't need more than one if statement). Test it yourself and you'll understand why it's so. Hope it helps.
The problem with this
void ft_list_clear(struct Node *begin_list)
{
if ((begin_list->next))
ft_list_clear(begin_list->next);
if(!(begin_list->next))
{
free(begin_list);
begin_list = NULL;
}
}
is:
In the first call, begin_list is equal to head.
head->next is not NULL, so ft_list_clear(second) is executed
second->next is not NULL, so ft_list_clear(third) is executed
third->next is NULL, so free(third) happens. The begin_list = NULL
line does nothing here, its pointless.
The third iteration returns, back to the second. The next line to execute is
if(!(begin_list->next))
begin_list->next is not NULL (it's been only freed), hence the condition is evaluated to false and the free
is not executed.
Same happens with the first iteration.
This is recursion that would work:
void ft_list_clear(struct Node *begin_list)
{
if(begin_list == NULL)
return;
ft_list_clear(begin_list->next);
free(begin_list);
}
Recursively deleting a linked is a bad idea. Each recursive call requires a stack frame, and whether you free the list node memory as you descend or ascend the recursion, you need O(n) memory for what is a simple operation. Each stack call requires local variable storage, room for return pointer, previous stack frame pointer, and possibly other stuff (at least 12-24 bytes per node).
Better to iterate through the list. I have provided three variants of the free (iterative, and two recursive, one free's node on descent, one free's node on ascent).
#include <stdlib.h>
#include <stdio.h>
typedef struct Node
{
int data;
struct Node* next;
} node_t;
long list_clear_iter(node_t* p) {
if(!p) return 0;
long n = 0; //count;
for( ; p->next; ) {
node_t* fp = p; //free this
p = p->next;
free(fp);
++n;
}
return n;
}
//list clear, recursive, (pre)free
long ft_list_clear_pr(node_t* p) {
if(!p) return 0;
node_t* np = p->next;
free(p); //free on descend
long n = ft_list_clear_pr(np);
return(n+1);
}
//list clear recursive, free(post)
long ft_list_clear_rp(node_t* p) {
if(!p) return 0;
long n = ft_list_clear_rp(p->next);
free(p); //free on ascend
return(n+1);
}
I'm implementing a linked list library to teach myself C. I've got most things working nicely except iteration, which is being used for the length function I've made. Here's the structs used for the list
typedef struct ListNode ListNode;
typedef struct List List;
struct ListNode {
void *val;
ListNode *next;
};
struct List {
ListNode *head;
};
I've also got a couple of other functions for manipulating the list, namely a create, push and pop function. Here's the create function if it matters:
List *list_create(){
List *list = malloc(sizeof *list);
return list;
}
Here's the function that's having issues, though:
int list_length(List *list){
ListNode *current = list->head;
int count = 0;
// Iterate through the list, adding to the count
while(current != NULL){
count++;
current = current->next;
}
return count;
}
For some reason when it reaches the last iteration, the while predicate doesn't work and instead, I get the following error:
Job 1, './linked_list ' terminated by signal SIGSEGV (Address boundary error)
Is there anything immediately obvious that I'm doing wrong? You can find all the (not completely working) code at https://github.com/tominated/linked_list
list_create leaves head uninitialised. list_push (in your github code) creates a new item and sets head to its next pointer. When you iterate through the list, the last item points to this uninitialised pointer rather than to NULL. From this point on, you are into undefined behaviour; the chances are high you'll quickly get a SIGSEGV.
The fix is simple - you just need to set head to NULL when you create the list.
List *list_create(){
List *list = malloc(sizeof *list);
if (list != NULL) {
list->head = NULL;
}
return list;
}
I am trying to implement a stack with linked lists. I am having problems with the pop() function. It compiles OK, but when I try to run the code it crashes on tmp=tmp->head; and I have no idea why. I tried google but didn't find the answer. Here is the full code:
struct node{ //kreiram stog
struct node* head;
struct node* next;
int broj;
}node;
void push_onto(int broj){ // dodajem na glavu
struct node* novi;
novi=(struct node*)malloc(sizeof(struct node));
//novi=novi->head;
if (novi== NULL)
printf("Smth is wrong,Jose!\n");
else
novi->broj=broj;
novi->next=novi->head;
novi->head=novi;
}
int pop()// skidam sa stoga
{
struct node* temp;
temp=temp->head;
int br;
if (temp->next==NULL)
return -1;
else
br=temp->head;
temp=temp->next;
free(temp);
return br;
}
void top(){ //koji je element na stogu
struct node* tmp;
printf("Trenutni element na stogu je %d",tmp->broj);
}
void is_empty(){
struct node* tmp;
tmp=tmp->head;
if (tmp->head ==NULL)
printf("List is empty!\n");
}
void print_elem(){
struct node* tmp;
tmp=tmp->head;
if (tmp->head==NULL)
printf("Smth gone wrong!\n");
while (tmp!=NULL)
{
printf("Number is: %d",tmp->broj);
tmp=tmp->next;
}
printf("\n");
}
int main(void){
push_onto(15);
push_onto(10);
push_onto(20);
push_onto(12);
//print_elem();
printf("The element removed is : %d",pop());
//print_elem();
return 0;
}
This is not my homework, although it looks as such. This is just my attempt at trying to figure out some basic algorithms.
Thanks in advance! :)
struct node* temp;
temp=temp->head;
You never allocated anything for temp. It's just an uninitialized pointer.
It's not clear what you are trying to pop. Your pop() function takes no parameters and it accesses no globals. Likewise, I see the same problem with most of your functions there. They are supposed to operate on some sort of stack object, but none of them actually take such an object as a parameter.
I think you're close to "getting it". I remember it was a bit hard for me to understand structs and pointers at the beginning. But once you "get it" you'll be fine.
It seems you're trying to construct a stack using a simply-linked list. I'll try to offer some suggestions.
The very first thing that I would modify is your node struct. It is true, you need to keep
track of the head node, but usually you don't need to do it on every node. So we will remove it from your node definition.
struct node{ //kreiram stog
struct node* next;
int broj;
};
Now, you need to keep track of the head node of your list. This can be done with a global variable, that I'm going to call head:
struct node* head = NULL;
I'm initializing it to null because it is empty. A null head pointer will always mean
your stack is empty. All the code that tries to manipulate the list WILL need to start
with this head node. It is your anchor point.
Then to the push_onto() function
void push_onto(int broj){ // dodajem na glavu
// this bit is fine
struct node* novi;
novi=(struct node*)malloc(sizeof(struct node));
if (novi== NULL)
printf("Smth is wrong,Jose!\n");
else { //I'm adding the bracket, you require it to enclose more than one statement
//in the else section
novi->broj = broj; // store the number to be pushed on the stack
novi->next = head; // link the list, remember head will
// be NULL if the stack was empty
head = novi; // make the new node the current head node
}
}
Let's modify the pop() function
int pop()// skidam sa stoga
{
struct node* temp;
int result;
// first we will check if the head node is NULL (stack is empty)
if( head == NULL ) {
printf("Stack is empty\n");
return -1;
} else {
// hold a temporary value to current head pointer, so we can modify the head node
// and still refer to it
temp = head;
// Head node should now point to the next node on the list (will become NULL when
// popping the last value. This is what actually "pops" the value from our list
head = head->next;
// place in temporary variable the result we are popping. This is so because
// it's not a good idea to reference the node after we free the memory it is using
result = temp->broj;
// release the memory occupied by the node we're popping
free(temp);
return result;
}
}
Finally I'm going to show you how to fix some of the functions that are using your stack
void top(){ //koji je element na stogu
if( head == NULL ) {
printf("Stack is empty\n");
} else {
printf("Trenutni element na stogu je %d",head->broj);
}
}
void print_elem(){
struct node* tmp;
// As you can see, we're initializing tmp to head, since head will always point
// to the top element of your stack.
tmp = head;
if (tmp==NULL) {
printf("Stack is empty!\n");
return;
}
while (tmp!=NULL)
{
printf("Number is: %d",tmp->broj);
tmp=tmp->next;
}
printf("\n");
}
Hope things are clearer now. The head node is kept apart as a global variable and as I said before, it is the anchor point to begin manipulating the list. Feel free to ask me if you're still confused.
=)
This is something of a followup to a question I asked earlier. I'm still learning my way around pointers, and I'm finding it difficult to maintain a reference to the physical address of a struct while iterating through a data structure. For example, I have a simple, barebones linked list that I'd like to delete from via a searching pointer:
struct Node{
int value;
struct Node* next;
};
struct Node* createNode(int value){
struct Node* newNode = malloc(sizeof *newNode);
newNode->value = value;
newNode->next = NULL;
return newNode;
}
void nodeDelete(Node **killptr){
free(*killptr);
*killptr = NULL;
}
int main(){
struct Node* head = createNode(16);
head->next = createNode(25);
head->next->next = createNode(51);
head->next->next->next = createNode(5);
// Working code to delete a specific node with direct reference address
struct Node** killptr = &head->next;
nodeDelete(killptr);
return 0;
}
The above shows deleting by passing nodeDelete a pointer to the address of the head pointer. What I want to do is be able to move my pointer ->next until it finds something that satisfies a delete condition, and call nodeDelete on that. I've tried the following:
struct Node* searchAndDestroy = head;
while(searchAndDestroy->value != NULL){ // Search until the end of the structure
if (searchAndDestroy->value == 25){ // If the value == 25
nodeDelete(&searchAndDestroy); // Delete the node (FAILS: Nullifies the
// address of search variable, not the
break; // original node)
}else{
searchAndDestroy = searchAndDestroy->next;
}
}
I've also tried something along the lines of:
if (searchAndDestroy->value == 25){
struct Node** killptr = (Node**)searchAndDestroy);
nodeDelete(killptr); // Still fails
}
I need to be able to move my pointer to the ->next point, but also maintain a reference to the address of the node I want to delete (instead of a reference to the address of the search node itself).
EDIT: Some clarification: I realize that deleting from a linked list in this fashion is naive, leaks memory, and drops half the list improperly. The point is not to actually delete from a linked list. Ultimately the idea is to use it to delete the leaves of a binary search tree recursively. I just figured a linked list would be shorter to portray in the question as an example.
struct Node **searchAndDestroy;
for (searchAndDestroy = &head;*searchAndDestroy; searchAndDestroy = &(*searchAndDestroy)->next ){
if ((*searchAndDestroy)->value == 25){
nodeDelete(searchAndDestroy); // Function should be changed to assign the ->next pointer to the **pointer
break;
}
}
And change nodeDelete like this:
void nodeDelete(Node **killptr){
Node *sav;
if (!*killptr) return;
sav = (*killptr)->next;
free(*killptr);
*killptr = sav;
}
Unless I'm missing something, your nodeDelete function is working as designed, but you want to keep a way of accessing the next node in the chain. The easiest way of doing this is just to add a temporary variable:
struct Node *searchAndDestroy = head, *temp = NULL;
while(searchAndDestroy != NULL){ // Need to check if the node itself is null before
// dereferencing it to find 'value'
temp = searchAndDestroy->next;
if (searchAndDestroy->value == 25){
nodeDelete(&searchAndDestroy);
break;
}else{
searchAndDestroy = temp;
}
}
if you give the Address of the previous Node that is where the link to deleting node present then it is very simple
code snippet for that:-
void delete_direct (struct Node *prevNode)
{/*delete node but restrict this function to modify head .So except first node use this function*/
struct Node *temp;/*used for free the deleted memory*/
temp=prevNode->link;
prevNode->link=temp->link;
free(temp);
}
struct Node * find_prev(struct Node *trv_ptr,int ele)
{
/*if deleting element found at first node spl operation must be done*/
if(trv_ptr->data==ele)
return trv_ptr;
while((trv_ptr->link)&&(trv_ptr->link->data!=ele))
{
trv_ptr=trv_ptr->link;
}
if(trv_ptr->link==NULL)
{
return NULL;
}
else
return trv_ptr;
}
main()
{
/*finding Node by providing data*/
struct Node *d_link;
struct Node *temp;
d_link=find_prev(head,51);
if(d_link==NULL)
{//data ele not present in your list
printf("\nNOT FOUND\n");
}
else if(d_link==head)
{//found at first node so head is going to change
temp=head;
head=head->link;
free(temp)
}
else
{//other wise found in some where else so pass to function
delete_direct (d_link);
}
}