Simpler and faster code for reversing list? - c

I wrote the code for reversing a doubly linked list containing words in each node, which works perfectly fine.
My teacher says the algorithm is difficult to understand and the code as a whole could be made more efficient(reducing overhead and memory consumption). What changes can i make to the code/the reversing algorithm?
Also is there a way i could input the sentence without having to ask the number of words in advance? Here is the code:
#include<stdio.h>
#include<conio.h>
#include<string.h>
typedef struct NODE
{
char *item;
struct NODE *next;
struct NODE *prev;
}NODE;
void Insert(char data[],NODE **List)
{
NODE *temp,*last;
last=(*List);
temp=(NODE*)malloc(sizeof(NODE));
temp->item=(char*)malloc(strlen(data));
temp->item=data;
temp->next=NULL;
temp->prev=NULL;
if((*List)->item==NULL)
(*List)=temp;
else
{
while(last->next!=NULL)
last=last->next;
temp->prev=last;
last->next=temp;
last=temp;
}
}
void Reverse(NODE **List)
{
int flag1=0;
NODE *temp,*temp1,*last,*flag;
temp1=(NODE*)malloc(sizeof(NODE));
last=(*List);
while(last->next!=NULL)
last=last->next;
temp=last;
while(temp->prev!=NULL)
{
temp1->item=temp->item;
temp1->next=temp->next;
temp1->prev=temp->prev;
temp->next=temp->prev;
temp->prev=temp1->next;
temp=temp->next;
if(flag1==0)
{
flag1++;
flag=temp;
}
}
temp1->item=temp->item;
temp1->next=temp->next;
temp1->prev=temp->prev;
temp->next=NULL;
temp->prev=temp1->next;
(*List)=flag->prev;
free(temp1);
};
void display(NODE *List)
{
if(List->next==NULL)
{
printf("%s",List->item);
return;
}
NODE *temp;
temp=List;
do
{
printf("%s<-->",temp->item);
temp=temp->next;
}while(temp->next!=NULL);
printf("%s\n",temp->item);
}
int main()
{
int i=0,n;
char s[10][50];
NODE *List;
List=(NODE*)malloc(sizeof(NODE));
List->item=NULL;
List->next=NULL;
List->prev=NULL;
printf("Provide number of words(max 10): ");
scanf("%d",&n);
printf("Enter string of words for the list: ");
while(i<n)
{
scanf("%s",s[i]);
Insert(s[i],&List);
i++;
}
printf("\nOriginal List is: ");
display(List);
Reverse(&List);
printf("\nReversed List is: ");
display(List);
getch();
return 0;
}

Since it's a double-linked list you could just write two traversal functions. One forward and one reverse. Save two anchors for your list in your control structure: one for the first element and one for the last.

You can just swap the next and previous pointers for each node and swap tail and head pointers.

void reverse (struct node *ptr)
{
struct node *tmp, *kid;
if (!ptr) return;
for (kid = ptr->next; kid; kid = kid->prev) {
tmp = kid->prev;
kid->prev = kid->next;
kid->next = tmp;
}
for (kid = ptr->prev; kid; kid = kid->next) {
tmp = kid->prev;
kid->prev = kid->next;
kid->next = tmp;
}
tmp = ptr->prev;
ptr->prev = ptr->next;
ptr->next = tmp;
return;
}
Note: I removed the typedef. I hate typedefs.

Related

Linked list in c returns negative number instead of adding node

Can someone explain to me why this code returns a random negative number instead of adding the node as it should? If the call to addnode is removed the main function works as it should so the problem lies with the addnode function. I don't think it's malloc that has the problem and I can't for the life of me figure out what is. Please help, I'm an amateur at c and I have a vague understanding of how pointers work so I guess something's wrong with my pointers. Here's the full code :
#include <stdio.h>
#include <stdlib.h>
struct node
{
int data;
struct node *next;
};
int addNode(struct node **head, int value);
void printList(struct node **head);
int main()
{
int value;
struct node *head;
head=NULL;
//int isempty(struct node *head);
for(int i=0;i<10;i++)
{
printf("\nInsert node value :");
scanf("%d",&value);
addNode(&head,value);
}
printList(&head);
return 0;
}
int addNode(struct node **head,int value)
{
struct node *newnode;
newnode=(struct node *) malloc(sizeof(struct node));
//if(newnode==NULL)
if(!newnode)
{
printf("Memory allocation error \n");
exit(0);
}
if(*head=NULL)
{
newnode->data=value;
newnode->next=NULL;
*head=newnode;
return 1;
}
else
{
struct node *current;
*current = **head;
while(current != NULL)
{
if(value<=(current->data)){
//περίπτωση 1ου κόμβου σε μη κενή λίστα
if(current==*head){
newnode->data=value;
newnode->next=*head;
*head=newnode;
return 1;
}
//περίπτωση ενδιάμεσου κόμβου
newnode->data=value;
return 1;
}
current = current->next;
}
}
}
/*int isempty(struct node *head){
return (head==NULL);
}*/
void printList(struct node **head) {
struct node *ptr = *head;
printf("\n[ ");
//start from the beginning
while(ptr != NULL) {
printf("(%d) ",ptr->data);
ptr = ptr->next;
}
printf(" ]");
return;
}
Well for starters you are having an assignment instead of a comparison in addNode
if(*head=NULL) should be if(*head==NULL)
Other than that, I think you are trying to maintain the elements in a sorted manner? But in any case you are manipulating pointers a bit more than you need to.

How to solve the pointer issue in the double linked list below?

Recently I learnt about doubly linked lists, and I have tried to write some code in C to implement them. The program below is supposed to receive integer inputs form the user and put them into a list with a maximum of ten integers. However, when I input the values and then print them, only the first and last values are output. How would one solve this issue?
Here is the code:
`#include <stdio.h>
#include <stdlib.h>
struct node {
struct node* prev;
int num;
struct node* next;
};
struct node *head,*p;
struct node* create_first_node(int x)
{
struct node *new = (struct node*)malloc(sizeof(struct node));
new->num=x;
new->prev=NULL;
new->next=NULL;
head=new;
p=head;
return new;
}
void add_node(int x)
{
struct node*new=(struct node*)malloc(sizeof(struct node));
new->num=x;
new->prev=p;
p->next=new;
(new->next)=NULL;
new=p;
}
void print_list(){
struct node *temp= head;
printf("\nThe list is:\n");
while (temp!=NULL)
{
printf("%d\t",temp->num);
temp=temp->next;
}
}
int main(){
int in[10];
int len,i;
head=NULL;
printf("How many nodes would you like?(Max=10) \n");
scanf("%d",&len);
for (i = 0; i < len; i++)
{
if (head == NULL && i==0)
{
printf("Enter Value for node %d\n",i+1);
scanf("%d",(in+i));
create_first_node(in[0]);
}
else
{
printf("Enter Value for node %d\n",i+1);
scanf("%d",(in+i));
add_node(in[i]);
}
}
print_list(head);
return 0;
}`

Palindrom check of linkedlist

Here is the code i wrote to check if a singly linked list of integers is a palindrome or not.
#include<stdio.h>
#include<stdlib.h>
struct list
{
int data;
struct list *next;
};
struct list *insert(int data,struct list *node)
{
if(node==NULL)
{
node=(struct list *)malloc(sizeof(struct list));
node->data=data;
node->next=NULL;
}
else
{
struct list *newnode=(struct list *)malloc(sizeof(struct list));
newnode->data=data;
newnode->next=node;
node=newnode;
}
return node;
}
int palindrome(struct list *node,int n)
{
int i=0;int j=0;
int arr1[n],arr2[n];
struct list *current;
current=node;
while(current!=NULL)
{
arr1[i]=current->data;
i++;
current=current->next;
}
i=0;j=0;
for(i=n-1;i>=0;i--)
{
arr2[j]=arr1[i];
j++;
}
for(i=0;i<n;i++)
{
if(arr1[i]!=arr2[i])
{
return 0;
}
}
return 1;
}
void main()
{
int n;
scanf("%d",&n);
struct list *node=NULL;
int i=1;int value;
for(i=1;i<=n;i++)
{
scanf("%d",&value);
insert(value,node);
}
int status=palindrome(node,n);
printf("%d",status);
}
But the code returns 0 even in case of valid palindrome inputs like "121" and also in non - palindrome inputs like "154". Please help. Thanks
You need to write
node = insert(value,node);
in main. Otherwise the head node is not changed because the function insert deals with a copy of the node.

Infinite loop in insertion in linked list

While inserting node at end in linked list ,my code is running in infinite loop.
IDE Used-Eclipse
64 bit OS
#include<stdio.h>
#include<stdlib.h>
typedef struct Node
{
int info;
struct Node *next;
}node;
node *head;
node *ptr1;
void insert(int x);
void show();
int main()
{
int i,x,n;
puts("Enter number of elements\n");
scanf("%d",&n);
for(i=0;i<n;i++)
{
puts("Enter elements");
scanf("%d",&x);
insert(x);
}
show();
return 0;
}
//To insert the data in linked list
void insert(int x)
{
node *ptr;
ptr1=head;
ptr=(node*)malloc(sizeof(node));
ptr->info=x;
if(head==NULL)
{
ptr->next=head;
head=ptr;
}
else
{
ptr1->next=NULL;
ptr1=ptr;
}
}
//To print the details of list
//Unable to figure out this function
void show()
{
while(ptr1->next!=NULL)
{
printf("%d\n",ptr1->info);
ptr1=ptr1->next;
}
}
The ptr1 is set to head each time your code enters the insert function then setting it to ptr in the else subsection but nothing pointing to any previous items.
Here is an example in case you need one.
typedef struct Node
{
int info;
struct Node *next;
}node;
node *head = NULL;
void insert(int x);
void show();
int main()
{
int i,x,n;
puts("Enter number of elements\n");
scanf("%d",&n);
for(i=0;i<n;i++)
{
puts("Enter elements");
scanf("%d",&x);
insert(x);
}
show();
return 0;
}
void insert(int x)
{
node *ptr = (node*)malloc(sizeof(node));
ptr->info=x;
ptr->next=head; /* this will always add the new entry at the beginning of the list all you need it to initialize the head to NULL*/
head = ptr; /* move the head so that it points to the newly created list element */
}
void show()
{
node *ptr1 = head;
printf("%d\n",ptr1->info); /* print the head */
while(ptr1->next!=NULL) /* now walk the list remember it first looks if the next pointer in the list is null first then it jumps on next element in case it is not*/
{
ptr1=ptr1->next;
printf("%d\n",ptr1->info);
}
}
Remember to create a function to free up the list elements before exiting the main.
Your two functions can be simplified. A singly linked list is very easy to implement. I would also improve the functions by taking the list pointer as an argument, and in the case of insert() return the new head of the list: but get it working first! Note there is no reason or need to declare global variables when their only use is local to a function.
// insert new node at head of the list
void insert(int x) {
node *ptr = malloc(sizeof(node));
if (ptr == NULL) {
printf ("malloc failure\n");
exit (1);
}
ptr->info = x;
ptr->next = head; // append existing list
head = ptr; // new head of list
}
// show the linked list
void show() {
node *ptr = head; // start at head of list
while (ptr != NULL) {
printf("%d\n", ptr->info);
ptr = ptr->next; // follow the link chain
}
}
EDIT here is code to add to the tail of a linked list
// insert new node at tail of the list
void insert2(int x) {
node *tail = head;
node **last = &head;
node *ptr;
while (tail) {
last = &tail->next;
tail = tail->next;
}
ptr = malloc(sizeof(node));
if (ptr == NULL) {
printf ("malloc failure\n");
exit (1);
}
ptr->info = x;
ptr->next = NULL;
*last = ptr;
}

What is wrong with my code for singly linked list?

I'm working on a singly linked list in C. This is what I've written so far.
C program
#include<stdio.h>
#include<stdlib.h>
struct Node{
int value;
struct Node *next;
};
struct Node* init()
{
struct Node* head=NULL;
head=malloc(sizeof(struct Node));
head->value=-1;
return head;
}
int length(struct Node* head)
{
struct Node* current=head;
int length=0;
while(current!=NULL)
{
length++;
current=current->next;
}
return length;
}
void print(struct Node* head)
{
int i=0;
int len=length(head);
for(i=0;i<len;i++)
{
printf("%d%d",i,head[i].value);
printf("\n");
}
}
struct Node* insert(int data,struct Node* head)
{
struct Node* current=NULL;
if(length(head) > 0)
{
int val=head->value;
if (val==-1)
{
head->value=data;
head->next=NULL;
}
else
{
current=malloc(sizeof(struct Node));
current->value=data;
current->next=head;
head=current;
}
}
else
{
printf("List is empty");
}
return head;
}
int main()
{
/* printf("Hello"); */
struct Node *head=init();
head=insert(20,head);
head=insert(30,head);
head=insert(40,head);
print(head);
printf("%d",length(head));
return 0;
}
The output values I get are:
Index Value
0 40
1 0
2 0
and for length is 3. I'm not able to grasp what I'm doing wrong here in pointer manipulation.
One obvious problem is not setting next to NULL on init - that would fail when checking length on the empty list
But your real problem is the print function
You can't use:
head[i].value
That notation is only valid for arrays, you need to use next to find each member
The Init function should set Next to NULL
struct Node* init()
{
struct Node* head=NULL;
head=malloc(sizeof(struct Node));
head->value=-1;
head->next=NULL;
return head;
}
otherwise the first call to length return an undefined result ( or GPF ).
Here:
for (i = 0; i < len; i++)
{
printf("%d%d", i, head[i].value);
printf("\n");
}
You need to advance from one node to another with head = head->next in the same manner as you do it in length(). head[i] won't do it.
It's unclear why your init() and insert() are so unnecessarily complicated and I don't even want to try to guess why. I want to suggest a better insert() and no init():
struct Node* insert(int data, struct Node* head)
{
struct Node* current;
current = malloc(sizeof(struct Node));
current->value = data;
current->next = head;
return current;
}
And then you do this:
int main(void)
{
struct Node *head = NULL;
head = insert(20, head);
head = insert(30, head);
head = insert(40, head);
print(head);
printf("%d", length(head));
return 0;
}
The notation head[i].value is only valid for arrays but not for linked lists. Arrays and linked lists are completely different, allocation of memory towards arrays is premeditated where as for linked lists it's dynamic. That is the reason why we use pointers for linked lists.
In init() you didn't assign null which causes the loop to run infinite times when you call length() for first time.
I am posting the modified code of print function:
void print(struct Node* head)
{
int i=0;
int len=0;
struct Node* current=head;
for(i=0;i<len;i++)
{
printf("%d %d",i,current->value);
print("\n");
current=current->next;
}
}

Resources