I am trying to print the reverse linked list. But I am getting only one value. Where am I going wrong? Please bear with me as I am new to C.
#include<stdio.h>
#include<stdlib.h>
struct itemlist {
int value;
struct itemlist *next;
};
typedef struct itemlist item;
int main(void) {
itemlist *curr,*head,*tail;
head=NULL;
tail=NULL;
for (int i = 1; i < 10; i++) {
curr=(itemlist *)malloc(sizeof(itemlist));
curr->value=i;
curr->next=tail;
tail=curr;
if (!head)
head=curr;
}
curr=head;
while (curr) {
printf("Curr value is:%d\n",curr->value);
curr=curr->next;
}
return 0;
}
This code prints 1 to 9
#include<stdio.h>
#include<stdlib.h>
struct itemlist
{
int value;
struct itemlist *next;
};
typedef struct itemlist item;
int main(void)
{
itemlist *curr,*head,*prev;
head=NULL;
curr=NULL;
prev=NULL;
for(int i=1;i<10;i++)
{
curr = new itemlist;
curr->value = i;
curr->next = NULL;
if (head == NULL)
head = curr;
if(prev != NULL)
prev->next = curr;
prev = curr;
}
curr=head;
while(curr)
{
printf("Curr value is:%d\n",curr->value);
curr=curr->next;
}
return 0;
}
Seems like you should start print your list from tail, not from head.
Change
curr=head;
with
curr = tail;
Change curr=head to curr=tail
Below is a simple example illustrating a bi-directional linked list which should get you on your way to understanding linked lists
#include<stdio.h>
#include<stdlib.h>
typedef struct
{
int value;
struct itemlist *next;
struct itemlist *prev;
}itemlist;
void forward(itemlist *head)
{
itemlist *curr = head;
while(curr)
{
printf("Curr value is: %d\n", curr->value);
curr = curr->next;
}
}
void backward(itemlist *tail)
{
itemlist *curr = tail;
while(curr)
{
printf("Curr value is: %d\n", curr->value);
curr = curr->prev;
}
}
int main(void)
{
itemlist *curr,*head,*tail;
head=NULL;
tail=NULL;
for(int i=1;i<10;i++)
{
curr=(itemlist *)malloc(sizeof(itemlist));
curr->value=i;
curr->next = NULL;
if(tail)
{
curr->prev = tail;
tail->next = curr;
}
tail=curr;
if(!head)
head=curr;
}
printf("Forwards\n");
forward(head);
printf("Backwards\n");
backward(tail);
return 0;
}
You don't need a tail at all, but only need a recursive function. The function points to next by itself before the printf.
void print_reverse(Itemlist *it){
if(it !=NULL){
print_reverse(it->next);
printf("Current value is:%d\n",it->value);
}
}
When you exit the loop your head (which was updated only once and when the first element was added) points to the last element.
The problem is that, in the first iteration, when you assign the next element of the current item:
curr->next=tail;
the value of tail is NULL, so the head of your list can't reach the rest of it
At least as I understand it, your plan is to create a linked list in reverse order, then print out its contents. If so, you probably want something like this:
#include <stdlib.h>
#include <stdio.h>
struct itemlist {
int value;
struct itemlist *next;
};
int main() {
struct itemlist *head = NULL;
struct itemlist *pos;
int i;
for (i=0; i<10; i++) {
struct itemlist *node = malloc(sizeof(*node));
node->value = i;
node->next = head;
head = node;
}
for (pos=head; NULL != pos; pos = pos->next)
printf("%d\n", pos->value);
return 0;
}
Note that you don't need a pointer to the "tail". The basic idea is pretty simple: start with head as an empty list (i.e., a null pointer). Insert each new node at the beginning of the list by setting its next pointer to the current beginning of the list, then setting the beginning of the list to point to the new node.
You're head and tail are mixed up:
The first Node (Node 0):
Value = 1
next = tail = NULL;
tail = Node 0
head = Node 0
The second Node (Node 1):
Value = 2
next = tail = Node 0
tail = Node 1
head = Node 0
Now you have
Node 1 -> Node 0 -> NULL
and head = Node 0 and tail = Node 1
So when you print you start at Node 0 (the "head" but it's actually the tail) Print the first node then end
You have to either switch head and tail to be the correct names or start printing with tail
Edit: Since you say you want them in order you can do this:
int main(void)
{
itemlist *curr,*head,*tail;
head=NULL;
tail=NULL;
for(int i=1;i<10;i++)
{
curr=(itemlist *)malloc(sizeof(itemlist));
curr->value=i;
curr->next = NULL;
//if there is something in the list add the current node after it
if(tail)
tail->next = curr;
//Update the tails so it's pointing to the current last node
tail = curr;
//Set the head ONCE
//this will happened the first time when if(tail) fails
if(!head)
head=curr;
}
//start at the head
curr=head;
while(curr)
{
printf("Curr value is:%d\n",curr->value);
curr=curr->next;
}
return 0;
}
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.
struct node {
struct node *next;
int num;
} Node;
Node *insert(int i) {
Node *head;
for (int c = 0; c < i; c++) {
head = malloc(sizeof(Node));
head.num = i;
head = head->next;
}
}
The insert function is supposed to create a linked list and add numbers from 0 to i to that linked list. However, it is also supposed to return a pointer to the beginning of the list/the list itself and I can't seem to figure out how to do it. I've tried to make a pointer and set it equal to head after adding the first node, but it only returns the first node and not the entire list. Can someone please help? Thanks.
You probably want to remember the previous node, so you can assign its next pointer. When you add a node, set its next pointer to the old head, and it now becomes the new head of the list. Which you can just return after the last iteration of the loop.
Node *insert(int i) {
Node *head, *prev = NULL;
for (int c = 0; c < i; c++) {
head = malloc(sizeof(Node));
head->num = i;
head->next = prev;
prev = head;
}
return head;
}
Update: to insert each new element at the end of the list, you need a bit more bookkeeping:
Node *insert(int i) {
Node *last_node = NULL;
Node *first_node = NULL;
for (int c = 0; c < i; c++) {
Node *node = malloc(sizeof(Node));
node->num = i;
node->next = NULL;
if (!last_node) {
// Remember the first node, so we can return it.
first_node = node;
}
else {
// Otherwise, append to the existing list.
last_node->next = node;
}
last_node = node;
}
return first_node;
}
It is as simple as introducing another variable. You currently have head to track the head of the list; add another to track the tail of the list:
struct node {
struct node *next;
int num;
} Node;
Node *insert(int i) {
Node *head;
Node *tail;
head = malloc(sizeof(Node));
head.num = 0;
tail = head;
for (int c = 1; c < i; c++) {
// allocate a new node at the end of the list:
tail->next = malloc(sizeof(Node));
// set "tail" to point to the new tail node:
tail = tail->next;
tail->num = c;
}
return head;
}
You could also add a special case for i == 0, if necessary.
By the way - and I realise this is possibly a task given to you as an exercise - but insert is a terrible name for a function that actually creates and fills an entirely new list.
I know there are multiple questions on the same problem on SO. But somewhere, I am not able to get the logic.
The function that reverses the Linked List is as follows:
void reverse()
{
struct node *curr=head, *prev=NULL;
while(curr!=NULL)
{
curr->next = prev;
prev = curr;
curr = curr->next;
}
head = prev;
}
I am using a global head pointer and the structure of a node in the linked list is:
struct node
{
int data;
struct node *next;
};
struct node *head = NULL;
Here, every time the curr node will point to the prev node and at the end when the list is traversed by the curr node, prev node will point to the last node in the list which I make as the head pointer.
But, this logic doesn't reverse the list and only prints the first node. So, I think the code is executed only once but I am not able to catch the mistake.
The other functions to make the program complete:
#include <stdio.h>
#include <stdlib.h>
struct node
{
int data;
struct node *next;
};
struct node *head = NULL;
void add(int n)
{
struct node *temp = (struct node*)malloc(sizeof(struct node));
temp->data = n;
temp->next = NULL;
if(head == NULL)
{
head = temp;
return;
}
temp->next = head;
head = temp;
}
void print()
{
struct node *temp = head;
printf("\n The List is : ");
while(temp!=NULL)
{
printf(" %d ",temp->data);
temp = temp->next;
}
}
void reverse()
{
struct node *curr=head, *prev=NULL;
while(curr!=NULL)
{
curr->next = prev;
prev = curr;
curr = curr->next;
}
head = prev;
}
int main(void)
{
add(1);
add(2);
add(3);
add(4);
add(5);
print();
reverse();
print();
return 0;
}
You are overwriting the curr->next pointer which is then used to iterate the list. Code should be more like this:
void reverse()
{
struct node *curr=head, *prev=NULL;
struct node *next;
while(curr!=NULL)
{
next = curr->next;
curr->next = prev;
prev = curr;
curr = next;
}
head = prev;
}
I am inserting node at the end of the list but my code is printing only the first element and running in infinite loop.
I am unable to figure out the error in my code.
typedef struct nodetype
{
int info;
struct nodetype* next;
}node;
node *head=NULL;
void insertatend(int x);//x is the key element.
void print();
void insertatend(int x)
{
node *ptr;
ptr=(node*)malloc(sizeof(node));
ptr->info=x;
if(head==NULL)
{
ptr->next=ptr;
head=ptr;
}
else
ptr->next=ptr;
}
void print() //To print the list
{
node *temp=head;
printf("List is-");
while(temp!=NULL)
{
printf("%d",temp->info);
temp=temp->next;
}
}
Consider your insert method (I will take head as a parameter here instead of a global)
void insertatend(node **hd, int x) {
node *ptr = NULL, *cur = NULL;
if (!(ptr = malloc(sizeof (node)))) {
return;
}
if (!*hd) {
*hd = ptr;
} else {
cur = *hd;
while (cur->next) {
cur = cur->next;
}
cur->next = ptr;
}
}
You need to traverse your list from the end to its back in order to perform the insertion correctly. (Hence the while loop in the above function).
Your "temp != NULL" will never become false after the insertion, because in that insertion you set the next pointer to itself, thus creating a link loop.
it should be more like this:
void insertatend(int x)
{
node *ptr;
ptr=malloc(sizeof(node)); //don't cast pointers returned by malloc
ptr->info=x;
ptr->next=NULL; //set next node pointer to NULL to signify the end
if(head==NULL)
{
head=ptr;
}
else
{
node* tmp = head;
while(tmp->next) tmp = tmp->next; //get last node
tmp->next=ptr; //attach new node to last node
}
}
also your else branch was incorrect, creating another link loop.
You need to pass the last element of the list:
void insertatend(node *last, int x)
Or put a a tail node as global:
node *head = NULL;
node *tail = NULL;
void insertatend(int x)
{
node *ptr;
ptr = malloc(sizeof(node)); /* Don't cast malloc */
ptr->info = x;
ptr->next = NULL;
if (head == NULL) {
head = ptr;
} else {
tail->next = ptr;
}
tail = ptr;
}
You could also redefine your node struct to include next, prev, head, and tail pointers and manipulate them appropriately.
In your case, you should only need to set the head pointer on the tail node and the tail pointer on the head node. Set next and prev on all nodes. head pointer on head node should point to itself; tail pointer on tail node should point to itself. Head->prev = NULL; Tail->next = NULL;
Then just pass the head pointer always to your insertatend func.
I want to add a insert method for my linked list that would insert onto what's already in the linked list (append values).
Here's my code now:
struct node {
char value;
struct node *next;
};
typedef struct node item;
void main() {
InsertChar('a');
InsertChar('b');
InsertChar('c');
}
void InsertChar(char s) {
item *curr, *head;
head = NULL;
curr = (item *)malloc(sizeof(item));
curr->value = s;
curr->next = head;
head = curr;
while(curr) {
printf("%c", curr->value);
curr = curr->next;
}
printf("\n");
}
The problem is that in the console it prints
a
b
c
I need it to print something more like
a
ab
abc
After calling the 3 InsertChar methods in main().
How can I do this?
Your problem is that the head is declared locally in the function, and when you leave the function, you loose it. When you come to the function again, you create it from scratch, etc.
So you need to pass head as an argument to your InsertChar function.
Also, if you want to see a, ab, abc output, you need to add elements to the tail of your list, rather than to the head as you do it now. In order to achieve that, you either need to store a separate pointer for tail or every time traverse to the last element.
You have to be keeping track of the head of your list. E.g.:
struct node {
char value;
struct node *next;
};
typedef struct node item;
item* head = NULL;
item* curr = NULL;
void InsertChar(char s) {
item* c = (item *)malloc(sizeof(item));
c->value = s;
c->next = NULL;
if (head)
curr->next = c;
else
head = c;
curr = c;
for (c = head; c; c = c->next)
printf("%c", c->value);
printf("\n");
}
void main() {
InsertChar('a');
InsertChar('b');
InsertChar('c');
}
This outputs:
a
ab
abc
There are two problems :
The list's is redefined each time the function is invoked.
you should start from the head of the list when you access the list's elements
This should fix your problem :
struct node {
char value;
struct node *next;
};
typedef struct node item;
item * head = NULL; // global
void main() {
InsertChar('a');
InsertChar('b');
InsertChar('c');
}
void InsertChar(char s) {
item *curr, *temp;
curr = (item *)malloc(sizeof(item));
curr->value = s;
curr->next = head;
head = curr;
temp = head;
while(temp) {
printf("%c", temp->value);
temp = temp->next;
}
printf("\n");
}