Removing unique elements in a doubly linked list in C - c

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.

Related

removing elements & memory management in linked lists in c

there! I've been working on data structures & algorithms. One thing that has been bothering me a lot, is linked list.
I've check a lot of linked list code samples, but one thing that I have noticed in every single one of them, is how they create node structs & make the user link them together.
So I started searching ways of creating linked lists in different languages & porting them to C. I found a tutorial that worked with Java. After porting the code, insertion was working fine, but removing gives me seg faults.
I think it's working this way, since in Java, we have garbage collectors & the fact that after malloc() you need to free() the memory, but no matter, how much I thought about it, I couldn't wrap my head, to where I should put free(). So the struct is memory unsafe as well.
So my real problem is were I should use free() in this code(maybe the seg fault is for a completely different reason, who knows).
#include <stdlib.h>
struct node {int value; struct node* next;};
typedef struct {struct node* first; struct node* last;} linkedList;
void initializeLinkedList(linkedList* list)
{
list->first = list->last = NULL;
}
// O(1)
void addLastLinkedList(linkedList* list, int element)
{
// create a new node
struct node* insertionNode = malloc(sizeof(struct node));
insertionNode->value = element;
// check if the linked list is empty
if (list->first==NULL) list->first = list->last = insertionNode;
else
{
// make last node point to this node
list->last->next = insertionNode;
// make the last node, this node
list->last = insertionNode;
}
}
// O(1)
void addFirstLinkedList(linkedList* list, int element)
{
// create a new node
struct node* insertionNode = malloc(sizeof(struct node));
insertionNode->value = element;
// check if the linked list is empty
if (list->first==NULL) list->first = list->last = insertionNode;
else
{
// make node point to the first node
insertionNode->next = list->first;
// make it the first node
list->first = insertionNode;
}
}
// O(n)
int removeLastLinkedList(linkedList* list)
{
// check if the linked list is empty
if (list->first==NULL) return -1;
// check if the linked list only has a single item
if (list->first==list->last) list->first = list->last = NULL;
// get the last to second node
struct node* currentNode = list->first;
while (currentNode != NULL)
{
if (currentNode->next == list->last) break;
currentNode = currentNode->next;
}
// set the last node to the second to last node
list->last = currentNode;
list->last->next = NULL;
}
// O(1)
int removeFirstLinkedList(linkedList* list)
{
// check if the linked list is empty
if (list->first==NULL) return -1;
// check if the linked list only has a single item
if (list->first==list->last) list->first = list->last = NULL;
// get the second node
struct node* secondNode = list->first->next;
// remove the pointer of first node
list->first->next = NULL;
// make the second node, the first node
list->first = secondNode;
return 0;
}
Within the both functions addLastLinkedList and addFirstLinkedList you forgot to initialize to NULL the data member next of the new node. Add statement
insertionNode->next = NULL;
The function removeLastLinkedList invokes undefined behavior when the list contains only one node because after this if statement
if (list->first==list->last) list->first = list->last = NULL;
the control is passed further to this code snippet
struct node* currentNode = list->first;
//...
// set the last node to the second to last node
list->last = currentNode;
list->last->next = NULL;
where there is used the null pointer list->last to access data member next.
Also the function produces a memory leak because the removed node is not freed.
And the function returns nothing if the list was not empty.
At least rewrite the function like
int removeLastLinkedList(linkedList* list)
{
// check if the linked list is empty
if (list->first==NULL) return -1;
// check if the linked list only has a single item
if ( list->first == list->last )
{
free( list->first );
list->first = list->last = NULL;
}
else
{
// get the last to second node
struct node *currentNode = list->first;
while ( currentNode->next != list->last )
{
currentNode = currentNode->next;
}
free( currentNode->next );
// set the last node to the second to last node
list->last = currentNode;
list->last->next = NULL;
}
return 0;
}
Similar problems exist in the function removeFirstLinkedList
Rewrite the function like
int removeFirstLinkedList(linkedList* list)
{
// check if the linked list is empty
if (list->first==NULL) return -1;
// check if the linked list only has a single item
if ( list->first == list->last )
{
free( list->first );
list->first = list->last = NULL;
}
else
{
// get the second node
struct node *secondNode = list->first->next;
free( list->first );
// make the second node, the first node
list->first = secondNode;
}
return 0;
}
Here is ANOTHER brief example of the four non-trivial functions in your OP.
While it is apparent that the code (and comments) is struggling to get things happening correctly, the long variable and function names make it difficult to read. This "less verbose" version may bring some clarity to seeing/thinking about what operations are being performed and in what sequence.
The first two functions below deal with the "head" of the linked list. They are somewhat easier and "set the mood" before reading the second two functions that deal with the "tail".
// Use typedefs and short conventional names
typedef struct node {
int value;
struct node *next;
} node_t;
typedef struct {
node_t *first;
node_t *last;
} ll_t;
// Short names!
void LLprepend( ll_t *p, int element ) {
node_t *nn = calloc( 1, sizeof *nn ); // omitting verification
nn->value = element;
nn->next = p->first; // Always
p->first = nn;
if( p->last == NULL ) // first node on list
p->last = nn;
}
int LLtrimhead( ll_t *p ) {
if( p->first == NULL )
return -1;
node_t *pDel = p->first; // target node being removed
p->first = p->first->next; // advance ptr (may be NULL)
free( pDel ); // <<===
if( p->first == NULL ) // list now empty??
p->last = NULL;
return 0;
}
// Short names!
void LLappend( ll_t *p, int element ) {
// calloc initializes all bytes to NULL
node_t *nn = calloc( 1, sizeof *nn ); // omitting verification
nn->value = element; // store data
if( p->last == NULL )
p->first = p->last = nn; // first node on list
else
p->last = p->last->next = nn; // appended & adjusted
}
int LLtrimtail( ll_t *p ) {
if( p->last == NULL )
return -1;
node_t *pPen = p->first; // "Penultimate" node
// traverse to penultimate node
while( pPen->next && pPen->next->next )
pPen = pPen->next;
if( pPen == p->first ) { // Only 1 node on list
free( pPen ); // <<===
p->first = p->last = NULL;
return 0;
}
free( pPen->next ); // <<===
p->last = pPen; // last becomes what was 2nd last
return 0;
}

why free function causes infinite loop?

I created a program in c which :
Creates a simple linked list in c in which I store letters
Print the content of every node
delete the last node
Print the content of the list again
The problem is with the "delete_last" function because prints in terminal an infinite loop (I believe that the problem is invoked when I use free funtion.)
#include<stdio.h>
#include<stdlib.h>
typedef struct node {
char xar;
struct node *next;
}Node;
void insert_list(Node **head , int len)
{
char x;
Node **list;
Node *node1 , *node2;
node1=(Node*)malloc(sizeof(Node));
printf("Give 5 characters : ");
x=getchar();
node1->xar = x;
node1->next=NULL;
list=&node1;
int i=0;
for(i=1 ; i < len ; i++)
{ x=getchar();
node2 = (node*)malloc(sizeof(node));
node2->xar = x;
node2->next = NULL;
(*list) -> next = node2;
list = &(*list) -> next ;
}
*head=node1;
}
void print_list(Node *head)
{
Node**lpp;
for(lpp=&head ; *lpp!=NULL ; lpp=&(*lpp)->next)
{
printf("\n the chars are %c" , (*lpp)->xar);
}
}
void delete_last(Node *head)
{
Node **lpp;
lpp=&head;
while((*lpp)->next!=NULL)
{
lpp=&(*lpp)->next;
}
free(*lpp);
}
int main()
{
Node *kefali ;
kefali = NULL;
insert_list(&kefali , 5);
print_list(kefali);
printf("\n");
delete_last(kefali);
print_list(kefali);
return 0;
}
You mustn't access to freed objects.
In the delete_last functon, you called free() for one of the nodes, but you didn't update any pointers there. This will have the following call of print_list access a freed object, invoking undefined behavior.
You should add
*lpp = NULL;
after
free(*lpp);
To get the freed node out of the list.
Note that this won't work for removing the first (only) element in the list because the head is passed as a copy. You should change the function to accept a pointer to the head pointer to enable it remove the first element.
Your delete_last lacks a way of telling that the last element was deleted. Either pass a pointer to head or return a new head.
Further, it's way to complicated. Using lpp as pointer to pointer is not necessary - it only complicates the code. Keep it simple.
Here is an example which returns the new head.
Node* delete_last(Node *head)
{
if (head == NULL) return NULL; // empty list
if (head->next == NULL)
{
// Only one element...
free(head);
return NULL;
}
Node *prev = head;
Node *lpp = prev->next;
while (lpp->next)
{
prev = lpp;
lpp = prev->next;
}
prev->next = NULL;
free(lpp);
return head;
}
and call it like:
head = delete_last(head);
Here is an example which takes a pointer to head.
Node* delete_last(Node **head)
{
if (head == NULL) exit(1); // illegal call
if (*head == NULL) return NULL; // empty list
if ((*head)->next == NULL)
{
// Only one element...
free(*head);
*head = NULL;
return;
}
Node *prev = *head;
Node *lpp = prev->next;
while (lpp->next)
{
prev = lpp;
lpp = prev->next;
}
prev->next = NULL;
free(lpp);
}
and call it like:
delete_last(&head);
You do not update the previous node (you need to keep track on it when iterating)
This makes no sense as you take reference to the local variable head and it does not change the the head of list when last element is deleted.
Node **lpp;
lpp=&head;
To prevent double-pointer function returns the head. Assign it when called. If return value is NULL the last element was deleted
Node *delete_last(Node *head)
{
Node *lpp = NULL, *prev;
if(head)
{
lpp=head -> next;
prev = head;
while(lpp->next)
{
prev = lpp;
lpp = lpp -> next;
}
if(prev == head && lpp == NULL)
{
free(head);
head = NULL; //empty list
}
else
{
free(lpp);
prev -> next = NULL;
}
}
free(lpp);
return head;
}
You can also use double pointer to modify the head when needed:
void delete_last(Node **head)
{
Node *lpp = NULL;
if(head && *head)
{
if(!(*head) -> next)
{
free(*head);
*head = NULL;
}
else
{
lpp = *head;
while(lpp -> next -> next)
{
lpp = lpp -> next;
}
free(lpp -> next);
lpp -> next = NULL;
}
}
}

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.

Reverse linked list returning new linked list

I need to implement a function that reverses a linked list but i don't know how to return a newly formed linked list as a result.
typedef struct node_t* Node;
struct node_t {
int n;
Node next;
};
// create a new node with value n
Node nodeCreate(int n)
{
Node node = malloc(sizeof(*node));
if (node == NULL) return NULL;
node->n = n;
node->next = NULL;
return node;
}
// reversing the linked list
Node reverseList(Node list)
{
if (list == NULL) return NULL;
Node current, prev, next;
current = rev_head;
prev = NULL;
while( current != NULL)
{
next = current->next;
current->next = prev;
prev = current;
current = next;
}
list = prev;
return list;
}
This is the code I have written so far.
How do I insert this reverse linked list into a different new linked list within the function reverseList it self?
You are juggling around your nodes on the original list, and modifying then in place - which means you have only one list, and modify its nodes.
If that is what you want, your code might work (as soon as you fix things like the rev_head variable that appears from nowhere) - and the new head of the list, which is on your prev variable: which means your code should just work.
(It is important that the typedef don't hide the pointer though, I'd suggest changing that.)
What you seem not to have understood quite well is that for this kind o structure, any node works as the head of a list - there is no "list" type, just "node" types - and if you happen to pick any node in the middle of a list, that will just represent a partial list, starting from that node as well. So when you change your previous "last" node to point to its previous "antecessor" as its "next", that is it: that node is now the head.
(The exception to this "node == list" equality is while the reversing algorithm is running - at that point you have nodes that point in one direction and nodes that point in another, and the extra "next" and "prev" variables provide the needed information to fix things. If this was production code, this part of the code would have to be protected in a thread-lock)
Otherwise, if you want to produce a reversed copy of the list, you will have to copy the old nodes along the way, and just fix where they are pointing.
#include <stdlib.h>
#include <string.h>
typedef struct node_t Node;
struct node_t {
int n;
Node next;
};
// create a new node with value n
Node *nodeCreate(int n) {
Node *node = malloc(sizeof(*node));
if (node == NULL) return NULL;
node->n = n;
node->next = NULL;
return node;
}
void nodeCopy(Node *node_dst, Node *node_src) {
if (node_src == NULL || node_dst == NULL || abs(node_dst - node_src) < sizeof(Node)) {
return
}
memcpy(node_dst, node_src, sizeof(Node));
}
// reversing the linked list
Node *reverseList(Node *list) {
Node *new_list, *prev;
if (list == NULL) return NULL;
new_list = nodeCreate(0);
nodeCopy(new_list, list);
new_list->next=NULL;
prev = new_list;
while(list->next != NULL) {
list = list->next;
new_list = nodeCreate(0);
nodeCopy(new_list, list);
new_list->next=prev;
prev = new_list;
}
return new_list;
}
You can simply create a new node for every node in the original list and set the link in opposite order. Code could be:
Node createReversedList(Node node) {
Node result = NULL;
while (node != NULL) {
Node n = nodeCreate(node->n);
n->next = result;
result = n;
node = node->next;
}
return result;
}
There is a simple way in which you can reverse linked list
You can simply create a new linked list and add each node at the start of linked list which will create same linked list in reverse order
Node* revList(Node *start){
Node *startRev=NULL,*temp,*newNode;
temp = start;
while (temp->next!=NULL){
newNode = (Node *) malloc (sizeof(Node));
//Code for copying data from temp to new node
if(startRev == NULL){
startRev = newNode;
}
else {
newNode->next = startRev;
startRev = newNode;
}
temp = temp->next;
}
return startRev;
}

Linked List Delete Function Modification Issues in c

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;
}

Resources