I have to make a function which swaps the neighbor nodes in a linked list with sentinel. Something like this: 1-2-3-4-5 -> 2-1-4-3-5, but I don't know how to do that. Can somebody help me?
#include <stdio.h>
#include <stdlib.h>
typedef struct _listelem {
int a;
struct _listelem* next;
} listelem;
void reverse_pairs(listelem* a)
{
listelem* head = NULL;
listelem* tail = NULL;
head = a->next;
tail = a->next;
while (head->next != NULL)
{
head = head->next->next;
tail = head;
}
return head;
}
You did not show how the list with a sentinel node is built.
I suppose that the sentinel node is the first node in the list pointed to by the pointer head.
In this case the function can look the following way.
void reverse_pairs( listelem *head )
{
if (head)
{
for (; head->next && head->next->next; head = head->next->next)
{
listelem *tmp = head->next;
head->next = head->next->next;
tmp->next = head->next->next;
head->next->next = tmp;
}
}
}
As for your function implementation then it is incorrect at least because a function with the return type void may not have a statement like this
return head;
Also within this while loop
while (head->next != NULL)
{
head = head->next->next;
tail = head;
}
you are changing the local variables head and tail. Such changes do not influence on the original list.
If you have a circular list when the data member next of the last node points to the head (sentinel) node then the function can look the following way.
void reverse_pairs( listelem *head )
{
if (head)
{
for ( listelem *current = head;
current->next != head && current->next->next != head;
current = current->next->next)
{
listelem *tmp = current->next;
current->next = current->next->next;
tmp->next = current->next->next;
current->next->next = tmp;
}
}
}
While the answer from #VladFromMoscow shows the proper approach for swapping nodes in the list to accomplish your objective, if you are stuck passing a single pointer, and the function return type is fixed at void, then there is another way to go about it.
Instead of swapping nodes, you simply swap the int member value between nodes. Approaching the problem that way, the address of the first node never changes, so there is no need to pass the address of the list as a parameter.
The approach is simple. Take the current node, swap the integer value between the current and next node and advance past the nodes holding the swapped integers. To do so, you advance from the current node to the next and check if the node that follows next is NULL (marking the end of the list). If it is NULL, you are done. If it is not NULL, advance again and repeat. You can write the function either with a while() loop, e.g.
void reverse_pairs (listelem *head)
{
while (head && head->next) {
int tmp = head->a;
head->a = head->next->a;
head->next->a = tmp;
head = head->next;
if (head->next)
head = head->next;
}
}
Or, slightly less readable, using a for() loop and a ternary, e.g.
void reverse_pairs (listelem *head)
{
for (; head && head->next;
head = head->next->next ? head->next->next : NULL) {
int tmp = head->a;
head->a = head->next->a;
head->next->a = tmp;
}
}
Example Use/Output
With a normal list where the last pointer is NULL, your output printing the original list, calling reverse_pairs(), and then outputting the modified list would look as follows:
$ ./bin/lls_revpairs
1 2 3 4 5
2 1 4 3 5
Complete Test Code
The complete test code is included below. Compiling as normal will use the for() loop above, or adding the define -DUSEWHILE, to your compile string will cause the while() loop form of the function to be used:
#include <stdio.h>
#include <stdlib.h>
typedef struct _listelem {
int a;
struct _listelem* next;
} listelem;
/** add node at end of list, update tail to end */
listelem *add (listelem **head, int v)
{
listelem **ppn = head, /* pointer to pointer to head */
*pn = *head, /* pointer to head */
*node = malloc (sizeof *node); /* allocate new node */
if (!node) { /* validate allocation */
perror ("malloc-node");
return NULL;
}
node->a = v; /* initialize members values */
node->next = NULL;
while (pn) {
ppn = &pn->next;
pn = pn->next;
}
return *ppn = node; /* add & return new node */
}
#ifdef USEWHILE
/** reverse node pairs in list - while loop */
void reverse_pairs (listelem *head)
{
while (head && head->next) {
int tmp = head->a;
head->a = head->next->a;
head->next->a = tmp;
head = head->next;
if (head->next)
head = head->next;
}
}
#else
/** reverse node pairs in list - for loop + ternary */
void reverse_pairs (listelem *head)
{
for (; head && head->next;
head = head->next->next ? head->next->next : NULL) {
int tmp = head->a;
head->a = head->next->a;
head->next->a = tmp;
}
}
#endif
/** print all nodes in list */
void prn_list (listelem *l)
{
if (!l) {
puts ("list-empty");
return;
}
size_t i = 0;
for (listelem *n = l; n && i < 10; n = n->next, i++)
printf (" %d", n->a);
putchar ('\n');
}
int main (void) {
listelem *list = NULL;
for (int i = 1; i <= 5; i++)
add (&list, i);
prn_list (list);
reverse_pairs (list);
prn_list (list);
}
Related
I need a little help removing unique characters in a doubly linked list in C. So here's the logic I tried implementing: I counted the occurrence of each character in the doubly linked list. If it's occurrence is 1 time, then it is unique element and needs to be deleted. I'll be repeating the process for all elements. But my code in remove_unique_dll() function isn't working properly, please help me fix it. Here's my code-
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct node
{
char data;
struct node *next;
struct node *prev;
};
struct node *head, *tail = NULL; //Represent the head and tail of the doubly linked list
int len;
void addNode(char data)
{
struct node *newNode = (struct node*) malloc(sizeof(struct node)); //Create new node
newNode->data = data;
if (head == NULL)
{ //If dll is empty
head = tail = newNode; //Both head and tail will point to newNode
head->prev = NULL; //head's previous will point to NULL
tail->next = NULL; //tail's next will point to NULL, as it is the last node of the list
}
else
{
tail->next = newNode; //newNode will be added after tail such that tail's next points to newNode
newNode->prev = tail; //newNode's previous will point to tail
tail = newNode; //newNode will become new tail
tail->next = NULL; //As it is last node, tail's next will point to NULL
}
}
void remove_unique_dll()
{
struct node *current = head;
struct node *next;
struct node *prev;
int cnt;
while (current != NULL)
{
next = current->next;
cnt = 1;
//printf("!%c ",next->data);
while (next != NULL)
{
if (next->data == current->data)
{
cnt += 1;
next = next->next;
}
else
next = next->next;
//printf("#%c %d %c\n",next->data,cnt,current->data);
}
if (cnt == 1)
{
prev = current->prev;
//printf("#%c %d",prev->data,cnt);
if (prev == NULL)
{
head = next;
}
else
{
prev->next = next;
}
if (next == NULL)
{
tail = prev;
}
else
{
next->prev = prev;
}
}
current = current->next;
//printf("#%c ",current->data);
}
head = current;
}
void display()
{
struct node *current = head; //head the global one
while (current != NULL)
{
printf("%c<->", current->data); //Prints each node by incrementing pointer.
current = current->next;
}
printf("NULL\n");
}
int main()
{
char s[100];
int i;
printf("Enter string: ");
scanf("%s", s);
len = strlen(s);
for (i = 0; i < len; i++)
{
addNode(s[i]);
}
printf("Doubly linked list: \n");
display();
remove_unique_dll();
printf("Doubly linked list after removing unique elements: \n");
display();
return 0;
}
The output is like this-
If you uncomment the printf() statements inside remove_unique_dll() you'll notice that no code below inner while loop is being executed after inner while loop ends. What's the issue here and what's the solution?
Sample input- aacb
Expected output- a<->a<->NULL
Some issues:
You shouldn't assign head = current at the end, because by then current is NULL
The next you use in the deletion part is not the successor of current, so this will make wrong links
As you progress through the list, every value is going to be regarded as unique at some point: when it is the last occurrence, you'll not find a duplicate anymore, as your logic only looks ahead, not backwards.
When you remove a node, you should free its memory.
Not a big issue, but there is no reason to really count the number of duplicates. Once you find the first duplicate, there is no reason to look for another.
You should really isolate the different steps of the algorithm in separate functions, so you can debug and test each of those features separately and also better understand your code.
Also, to check for duplicates, you might want to use the following fact: if the first occurrence of a value in a list is the same node as the last occurrence of that value, then you know it is unique. As your list is doubly linked, you can use a backwards traversal to find the last occurrence (and a forward traversal to find the first occurrence).
Here is some suggested code:
struct node* findFirstNode(char data) {
struct node *current = head;
while (current != NULL && current->data != data) {
current = current->next;
}
return current;
}
struct node* findLastNode(char data) {
struct node *current = tail;
while (current != NULL && current->data != data) {
current = current->prev;
}
return current;
}
void removeNode(struct node *current) {
if (current->prev == NULL) {
head = current->next;
} else {
current->prev->next = current->next;
}
if (current->next == NULL) {
tail = current->prev;
} else {
current->next->prev = current->prev;
}
free(current);
}
void remove_unique_dll() {
struct node *current = head;
struct node *next;
while (current != NULL)
{
next = current->next;
if (findFirstNode(current->data) == findLastNode(current->data)) {
removeNode(current);
}
current = next;
}
}
You have at least three errors.
After counting the number of occurrences of an item, you use next in several places. However, next has been used to iterate through the list. It was moved to the end and is now a null pointer. You can either reset it with next = current->next; or you can change the places that use next to current->next.
At the end of remove_unique_dll, you have head=current;. There is no reason to update head at this point. Whenever the first node was removed from the list, earlier code in remove_unique_dll updated head. So it is already updated. Delete the line head=current;.
That will leave code that deletes all but one occurrence of each item. However, based on your sample output, you want to leave multiple occurrences of items for which there are multiple occurrences. For that, you need to rethink your logic in remove_unique_dll about deciding which nodes to delete. When it sees the first a, it scans the remainder of the list and sees the second, so it does not delete the first a. When it sees the second a, it scans the remainder of the list and does not see a duplicate, so it deletes the second a. You need to change that.
Let's consider your code step by step.
It seems you think that in this declaration
struct node *head, *tail = NULL; //Represent the head and tail of the doubly linked list
the both pointers head and tail are explicitly initialized by NULL. Actually only the pointer tail is explicitly initialized by NULL. The pointer head is initialized implicitly as a null pointer only due to placing the declaration in file scope. It to place such a declaration in a block scope then the pointer head will be uninitialized.
Instead you should write
struct node *head = NULL, *tail = NULL; //Represent the head and tail of the doubly linked list
Also it is a very bad approach when the functions depend on these global variables. In this case you will be unable to have more than one list in a program.
Also the declaration of the variable len that is used only in main as a global variable
int len;
also a bad idea. And moreover this declaration is redundant.
You need to define one more structure that will contain pointers head and tail as data members as for example
struct list
{
struct node *head;
struct node *tail;
};
The function addNode can invoke undefined behavior when a new node can not be allocated
void addNode(char data)
{
struct node *newNode = (struct node*) malloc(sizeof(struct node)); //Create new node
//...
You should check whether a node is allocated successfully and only in this case change its data members. And you should report the caller whether a node is created or not.
So the function should return an integer that will report an success or failure.
In the function remove_unique_dll after this while loop
while (next != NULL)
{
if (next->data == current->data)
{
cnt += 1;
next = next->next;
}
else
next = next->next;
//printf("#%c %d %c\n",next->data,cnt,current->data);
}
if cnt is equal to 1
if (cnt == 1)
//..
then the pointer next is equal to NULL. And using the pointer next after that like
if (prev == NULL)
{
head = next;
}
else
{
prev->next = next;
}
is wrong.
Also you need to check whether there is a preceding node with the same value as the value of the current node. Otherwise you can remove a node that is not a unique because after it there are no nodes with the same value.
And this statement
head = current;
does not make sense because after the outer while loop
while (current != NULL)
the pointer current is equal to NULL.
Pay attention that the function will be more useful for users if it will return the number of removed unique elements.
Here is a demonstration program that shows how the list and the function remove_unique_dll can be defined.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct node
{
char data;
struct node *next;
struct node *prev;
};
struct list
{
struct node *head;
struct node *tail;
};
int addNode( struct list *list, char data )
{
struct node *node = malloc( sizeof( *node ) );
int success = node != NULL;
if (success)
{
node->data = data;
node->next = NULL;
node->prev = list->tail;
if (list->head == NULL)
{
list->head = node;
}
else
{
list->tail->next = node;
}
list->tail = node;
}
return success;
}
size_t remove_unique_dll( struct list *list )
{
size_t removed = 0;
for ( struct node *current = list->head; current != NULL; )
{
struct node *prev = current->prev;
while (prev != NULL && prev->data != current->data)
{
prev = prev->prev;
}
if (prev == NULL)
{
// there is no preceding node with the same value
// so the current node is possibly unique
struct node *next = current->next;
while (next != NULL && next->data != current->data)
{
next = next->next;
}
if (next == NULL)
{
// the current node is indeed unique
struct node *to_delete = current;
if (current->prev != NULL)
{
current->prev->next = current->next;
}
else
{
list->head = current->next;
}
if (current->next != NULL)
{
current->next->prev = current->prev;
}
else
{
list->tail = current->prev;
}
current = current->next;
free( to_delete );
++removed;
}
else
{
current = current->next;
}
}
else
{
current = current->next;
}
}
return removed;
}
void display( const struct list *list )
{
for (const node *current = list->head; current != NULL; current = current->next)
{
printf( "%c<->", current->data );
}
puts( "null" );
}
int main()
{
struct list list = { .head = NULL, .tail = NULL };
const char *s = "aabc";
for (const char *p = s; *p != '\0'; ++p)
{
addNode( &list, *p );
}
printf( "Doubly linked list:\n" );
display( &list );
size_t removed = remove_unique_dll( &list );
printf( "There are removed %zu unique value(s) in the list.\n", removed );
printf( "Doubly linked list after removing unique elements:\n" );
display( &list );
}
The program output is
Doubly linked list:
a<->a<->b<->c<->null
There are removed 2 unique value(s) in the list.
Doubly linked list after removing unique elements:
a<->a<->null
You will need at least to write one more function that will free all the allocated memory when the list will not be required any more.
I wrote code to remove the node at the tail of a linked list. The code works properly in different testcases, but I think I made my code a bit cumbersome. However, I don't see what I can do differently?
node_t *remove_t (node_t *l){
if (l==NULL){
return l;
}
else {
node_t *curr=l;
node_t *ret=l;
if (curr->next==NULL){
l=NULL;
return l;
}
else {
while (curr->next->next!=NULL){
curr=curr->next;
}
curr->next=NULL;
free(curr->next);
return ret;
}
}
}
It is much, much easier if you keep a pointer-to-pointer to node, then iterate to the end of list and simply free the last pointer and set it NULL, e.g.
/** delete last node */
void del_last_node (node_t **l)
{
node_t **ppn = l; /* pointer to pointer */
node_t *pn = *l; /* pointer to node */
for (; pn->next; ppn = &pn->next, pn = pn->next) { } /* iterate to last */
free (*ppn); /* free node */
*ppn = NULL; /* set pointer NULL */
}
I'm not sure that you can change the logic much - as your approach of 3 different cases (empty list, list with 1 item, and list with >1 items) is reasonable. You can format the code for easier reading: Something like:
node_t *remove_t (node_t *l){
// case 1: Empty list
if (l==NULL){
return l;
} ;
// case 2: List with one item. Return empty list.
node_t *curr=l;
if (curr->next==NULL){
// Remember to free this element.
free(curr) ;
l=NULL;
return l;
} ;
// case 3: list > one item
// Move curr to last item
while (curr->next->next!=NULL){
curr=curr->next;
}
// Note order of free/null setting.
free(curr->next);
curr->next=NULL;
return l;
}
You didn't seem to free the tail node.
curr->next=NULL;
free(curr->next);
You won't be able to free curr->next if you already make it NULL.
My implementation:
void remove_tail(node_t *l) {
if (l == NULL) return;
if (l->next == NULL) {
free(l);
l = NULL;
return;
}
node_t *prev = l;
node_t *curr = l->next;
while (curr->next != NULL) {
prev = curr;
curr = curr->next;
}
prev->next = NULL;
free(curr);
}
I am studying for a test and I am having trouble debugging my linked list practice exam questions. I am having issues with the different modification to the delete functions he wants us to do. Specifically, my deleteEven is an endless look and my deleteNthNode does not work as it is supposed to. Because I am struggling with these two I'm not even sure where to start with deleting every other element in the list. I'd appreciate the help as I want to completely understand this topic before I move to stacks and queues! :)
Below is my code:
/*
Q1:
Try implementing the functions shown in class on your own:
check: node creation
check: insertion at the end of a linked list,
check: insertion at the head of a linked list,
check: a list printing function.
Q2:
check: Write a recursive printList() function.
Q3:
check: Write a recursive tailInsert() function.
Q4:
check: Write a function that inserts nodes at the beginning of the linked list.
Q5:
check: Write a recursive function that prints a linked list in reverse order.
The function signature is: void printReverse(node *head);
Q6:
check: Write an iterative destroyList() function that frees all the nodes in a linked list.
Q7:
check: Now implement destroyList() recursively.
Q8:
- Write a function that deletes the nth element from a linked list.
If the linked list doesn't even have n nodes, don't delete any of them.
The function signature is: node *deleteNth(node *head, int n).
- Try implementing the function iteratively and recursively.
- (In terms of how to interpret n, you can start counting your nodes from zero or one; your choice.)
Q9:
- Write a function that deletes every other element in a linked list.
- (Try writing it both ways: one where it starts deleting at the head of the list,
- and one where it starts deleting at the element just after the head of the list.)
- Can you write this both iteratively and recursively?
Q10:
- Write a function that deletes all even integers from a linked list.
Q11:
- Write a function that takes a sorted linked list and an element to be inserted into that linked list,
and inserts the element in sorted order.
The function signature is: node *insertSorted(node *head, int n);
Q12:
- One of the problems with the first insertNode() function from today is that it
requires us to call it using head = insertNode(head, i).
That's a bit dangerous, because we could forget the "head =" part very easily.
Re-write the function so that it takes a pointer to head,
thereby allowing it to directly modify the contents of head without any need for a return value.
The function signature is: void insertNode(node **head, int data).
The function will be called using insertNode(&head, i).
*/
//come back to
#include <stdio.h>
#include <stdlib.h>
// Basic linked list node struct; contains 'data' and 'next' pointer.
// What happens if we type "node *next" instead of "struct node *next"?
typedef struct node
{
// data field
int data;
// the next node in the list
struct node *next;
} node;
// Allocate a new node. Initialize its fields. Return the pointer.
// We call this from our insertion functions.
node *createNode(int data)
{
node *ptr = NULL;
ptr = malloc(sizeof(node));
if(ptr == NULL)
{
printf("space could not be allocated\n");
return NULL;
}
ptr->data = data;
ptr->next = NULL;
return ptr;
}
// Insert into the end of the linked list. Return the head of the linked list.
// (What is the order (Big-Oh) of this function?)
/*
node *insertNode(node *head, int data)
{
node *temp;
if (head == NULL)
return createNode(data);
for(temp = head; temp->next != NULL; temp = temp->next)
;
temp->next = createNode(data);
return head;
}
*/
node *insertNodeFront(node *head, int data)
{
node *temp;
if(head == NULL)
return createNode(data);
temp = createNode(data);
temp->next = head;
return temp;
}
// Simple function to print the contents of a linked list.
void printList(node *head)
{
if (head == NULL)
{
printf("Empty List\n");
return;
}
for(; head != NULL; head = head->next)
printf("%d ", head->data);
printf("\n");
}
void printListRecursiveHelper(node *head)
{
if (head == NULL)
return;
printf("%d%c", head->data, (head->next == NULL) ? '\n' : ' ');
printListRecursiveHelper(head->next);
}
void printListRecursive(node *head)
{
if (head == NULL)
{
printf("empty list\n");
return;
}
printListRecursiveHelper(head);
}
// Q3: - Write a recursive tailInsert() function.
node *tailInsert(node *head, int data)
{
if(head->next == NULL)
{
node *temp;
temp = createNode(data);
temp->next = NULL;
head->next = temp;
return temp;
}
return tailInsert(head->next, data);
}
//Q5: Write a recursive function that prints a linked list in reverse order.
void printReverse(node *head)
{
if (head == NULL)
return;
printReverse(head->next);
printf("%d ", head->data);
}
// Q6: - Write an iterative destroyList() function that frees all the nodes in a linked list.
// Got code from internet, memorize it
/* Function to delete the entire linked list */
void destroyList (struct node** head)
{
struct node* current = *head;
struct node* next;
while (current != NULL)
{
next = current->next;
free(current);
current = next;
}
*head = NULL;
}
// Q7: - Now implement destroyList() recursively.
// Look up online, need to examine why it deson't work
node *destroyListRecursive(node * head)
{
if (head != NULL)
{
destroyListRecursive(head->next);
free(head);
}
return NULL;
}
/* Q8:
- Write a function that deletes the nth element from a linked list.
- If the linked list doesn't even have n nodes, don't delete any of them.
- Try implementing the function iteratively and recursively.
- (In terms of how to interpret n, you can start counting your nodes from zero or one; your choice.)
*/
node *deleteNth(node *head, int n)
{
/*
int i;
node*current;
node *prev;
current = head;
while(i = 0; i < n; i++)
{
current = current->next;
}
prev = current;
current = head->next->next;
*/
return head;
}
/*
Q9:
- Write a function that deletes every other element in a linked list.
- (Try writing it both ways: one where it starts deleting at the head of the list,
- and one where it starts deleting at the element just after the head of the list.)
- Can you write this both iteratively and recursively?
*/
/* deletes alternate nodes of a list starting with head */
//got code from http://www.geeksforgeeks.org/delete-alternate-nodes-of-a-linked-list/
void deleteAltHead(struct node *head)
{
if (head == NULL)
return;
struct node *node = head->next;
if (node == NULL)
return;
/* Change the next link of head */
head->next = node->next;
/* free memory allocated for node */
free(node);
/* Recursively call for the new next of head */
deleteAltHead(head->next);
}
void deleteOtherTail()
{
}
//Q10: - Write a function that deletes all even integers from a linked list.
void deleteEvenInts(node **head)
{
}
// Q11: - Write a function that takes a sorted linked list and an element to be inserted into that linked list,
// and inserts the element in sorted order.
node *insertSorted(node *head, int n)
{
struct node *current;
struct node *newNode = createNode(n);
/* Special case for the head end */
if (head == NULL || head->data >= newNode->data)
{
newNode->next = head;
head = newNode;
}
else
{
/* Locate the node before the point of insertion */
current = head;
while (current->next != NULL &&
current->next->data < newNode->data)
{
current = current->next;
}
newNode->next = current->next;
current->next = newNode;
}
return current;
//or should it return head?
}
// Q12: Re-write the insertNode() function so that it takes a pointer to head
void insertNode(node **head, int data)
{
node *newNode = createNode(data);
while (*head != NULL)
{
head = &(*head)->next;
}
newNode->next = *head;
*head = newNode;
}
// Q10: Write a function that deletes all even integers from a linked list.
void deleteEven(node **head)
{
node *current = *head;
node *next = current;
node *prev = NULL;
for ( ; current != NULL; )
{
next = current->next;
if( current->data %2)
{
if(prev != NULL)
{
prev->next = next;
free(current);
current = next;
}
else
{
free(current);
current = next;
}
}
else
{
prev = current;
current = next;
}
}
}
//Q8: Write a function that deletes the nth element from a linked list. If the linked list doesn't even have n nodes, don't delete any of them.
node *deleteNthNode(node *head, int n)
{
int i = 0;
int nBigger = 0;
node *current = head;
node *prev = current;
for ( i = 0; i < n; i++)
{
prev = current;
current = current->next;
if (current == NULL)
{
nBigger = 1;
}
}
if(nBigger == 1)
{
return head;
}
prev = current->next;
free(current);
return head;
}
int main(void)
{
int i, r;
// The head of our linked list. If we don't initialize it to NULL, our
// insertNode() function might segfault.
node *head = NULL;
srand(time(NULL));
// Populate the linked list with random integers. We are inserting into the
// head of the list each time.
for (i = 0; i < 10; i++)
{
printf("Inserting %d...\n", r = rand() % 20 + 1);
insertNode(&head, r);
}
head = insertNodeFront(head, 1);
tailInsert(head, 5);
// Print the linked list.
printList(head);
printf("\n");
printReverse(head);
printf("\n\n");
// Print the linked list using our recursive function.
printListRecursive(head);
//destroyList(&head);
deleteAltHead(head);
printf("\n");
printList(head);
{
if (head == NULL)
return;
struct node *node = head->next;
if (node == NULL)
return;
/* Change the next link of head */
head->next = node->next;
/* free memory allocated for node */
free(node);
/* Recursively call for the new next of head */
}
deleteEven(&head);
// head = destroyListRecursive(head);
printf("\n");
printList(head);
node *head2 = NULL;
insertNode(&head2, 1);
insertNode(&head2, 2);
insertNode(&head2, 4);
printf("\n");
printList(head2);
insertSorted(head2, 3);
printf("\n");
deleteNthNode(head, 1);
printList(head2);
//destroyListRecursive(head2);
system("PAUSE");
return 0;
}
I'm trying to do some programming puzzles to learn C and I'm having trouble with getting a linked list deletion to work when deleting the head node. I think the problem is super simple but I can't find it!! The problem I'm having is with the delete() function, when I try to remove the head of a linked list it doesn't remove it, but instead changes it to a garbage value.
Can anyone help me out please? Thank you so much!
Here's example output:
Generating list...
Inserted: 0
Inserted: 1
Inserted: 2
Inserted: 3
Inserted: 4
List:
0 1 2 3 4
Deleted: 4
List:
0 1 2 3
Deleted: 0
List:
8344720 1 2 3
Here is my source code:
#include <stdlib.h>
#include <stdio.h>
typedef struct Node {
int value;
struct Node* next;
} node;
// Append a node to the end of the linked list
int insert(node* head, int value) {
node* current = head;
/* Check for sentinel value. If first element inserted, overwrite head instead of appending. */
if (head->value == 420) {
head->value = value;
head->next = NULL;
printf("\tInserted:\t%d\n", head->value);
return 0;
}
/* Traverse to end to append node */
while (current->next != NULL)
current = current->next;
/* Build new node and append to tail*/
current->next = malloc(sizeof(node));
current->next->value = value;
current->next->next = NULL;
printf("\tInserted:\t%d\n", current->next->value);
return 0;
}
/* Accept a number and delete all nodes containing that value */
int del(node* head, int value){
node* curr = head;
node* prev = NULL;
node* del = NULL;
printf("\tDeleted:\t%d\n", value);
if (head == NULL) {
printf("Can't delete value from empty list!\n");
return 1;
}
/* Search list remove all instances of value. Watch for edge cases. */
while (curr != NULL) {
if (curr->value == value){
/* Head case (lol) */
if (curr == head) {
del = head;
head = head->next;
curr = head;
free(del);
}
/* Tail case */
else if (curr->next == NULL) {
del = curr;
curr = prev;
curr->next = NULL;
free(del);
return 0; /* End of list, break out of loop to avoid segfaulting */
}
/* Body case (base case) */
else {
del = curr;
curr = curr->next;
prev->next = curr;
free(del);
}
}
prev = curr;
curr = curr->next;
}
return 0;
}
/* Accept head pointer and print until end of list */
int traverse(node* head) {
node* current = head;
if (head == NULL){
printf("Can't traverse null list!\n");
return 1;
}
printf("List:\n");
while(current != NULL) {
printf(" %d ", current->value);
current = current->next;
}
printf("\n");
return 0;
}
/* Let's begin our crazy experiment.... */
int main() {
node* head = NULL;
head = malloc(sizeof(node));
head->value = 420;
head->next = NULL;
printf("Generating list...\n");
int value;
for (value = 0; value < 5; value++)
insert(head, value);
traverse(head);
del(head, 4);
traverse(head);
del(head, 0);
traverse(head);
return 0;
}
You are modifying the head inside the del() function and using the old head from the main(). You need to pass the address of the head to del and modify it so that the change will reflect in main. You may need something like this.
int del(node **head, int value){
node* curr = *head;
....
And from the main
del(&head);
I have the following node structure in C:
#define SIZE 5
typedef struct node
{
int n;
struct node* next;
}node;
node* head = NULL;
void implement(int n); // create linked list
int length(void); // returns length of list
node* reverse(void); // reverses order of list
The list is implemented as follows:
void implement (int n)
{
for (int i = 0; i < n; i++)
{
node* new_node = malloc(sizeof(node));
if(new_node == NULL)
{
printf("out of memory!\n");
return;
}
new_node->n = i;
new_node->next = head;
head = new_node;
}
}
Which when printed to the terminal gives:
4 3 2 1 0
The head pointer is set to node 4.
I have written the following function to reverse the list as follows:
node* reverse(void)
{
node* cur = head;
node* next = NULL;
head = NULL;
while (cur->next != NULL)
{
next = cur->next;
cur->next = head;
head = cur;
cur = next;
}
return cur;
}
However, returning cur only gives:
0
Returning head provides:
1 2 3 4
So it is quite clear that the list is being reversed, but for some reason the last node (0) is not being linked to the remaining nodes. I am probably missing something obvious here, but can anyone give me any pointers? (no pun intended!)
Cheers
while (cur->next != NULL)
This stops when cur is at the last element (next is NULL); i.e. you don't process the last node.
Changing it to
while (cur != NULL)
and returning head should fix it.