hey for some reason my linked list is printing in the reversed ordear for example if my input is 2->4->6
my output is 6->4->2
list* add_int_list(list* a,int b)
{
list *temp;
temp = (list*)malloc(sizeof(list*));
temp->next = NULL;
if (a->next == NULL)//insert to the first node
{
temp->data = b;
temp->next = a;
a = temp;
}
else
{
temp->data = b;
temp->next = a;
a = temp;//I think the problem is here, couldnt find how to fix
}
For starters in this statement
temp = (list*)malloc(sizeof(list*));
^^^^^
there is allocated memory of the size equal to the size of pointer instead of the size of the node. You have to write either
temp = (list*)malloc(sizeof(list));
or
temp = (list*)malloc(sizeof( *temp));
This if statement
if (a->next == NULL)
can invoke undefined behavior because initially the list can be empty. So the pointer a can be equal to NULL. That is there is used a null pointer to access memory.
There is no difference between these two code blocks after the if and else parts of the if-else statement
if (a->next == NULL)//insert to the first node
{
temp->data = b;
temp->next = a;
a = temp;
}
else
{
temp->data = b;
temp->next = a;
a = temp;//
}
That is the both code snippet try insert a new-node in the beginning of the list.
It is a general approach to insert a new node in a singly-linked one-sided list in its beginning. To append a node to such a list to its end is inefficient because the whole list must be traversed.
If you want to append a node to the end of a singly linked list then make it two-sided.
Here is a demonstrative program.
#include <stdio.h>
#include <stdlib.h>
typedef struct Node
{
int data;
struct Node *next;
} Node;
typedef struct List
{
Node *head;
Node *tail;
} List;
int push_front( List *list, int data )
{
Node *new_node = malloc( sizeof( Node ) );
int success = new_node != NULL;
if ( success )
{
new_node->data = data;
new_node->next = list->head;
list->head = new_node;
if ( list->tail == NULL ) list->tail = list->head;
}
return success;
}
int push_back( List *list, int data )
{
Node *new_node = malloc( sizeof( Node ) );
int success = new_node != NULL;
if ( success )
{
new_node->data = data;
new_node->next = NULL;
if ( list->tail == NULL )
{
list->head = list->tail = new_node;
}
else
{
list->tail = list->tail->next = new_node;
}
}
return success;
}
void output( const List *list )
{
for ( const Node *current = list->head; current != NULL; current = current->next )
{
printf( "%d -> ", current->data );
}
puts( "null" );
}
int main(void)
{
List list = { .head = NULL, .tail = NULL };
const int N = 10;
for ( int i = 0; i < N; i++ )
{
if ( i % 2 != 0 )
{
push_front( &list, i );
}
else
{
push_back( &list, i );
}
output( &list );
}
return 0;
}
Its output is
0 -> null
1 -> 0 -> null
1 -> 0 -> 2 -> null
3 -> 1 -> 0 -> 2 -> null
3 -> 1 -> 0 -> 2 -> 4 -> null
5 -> 3 -> 1 -> 0 -> 2 -> 4 -> null
5 -> 3 -> 1 -> 0 -> 2 -> 4 -> 6 -> null
7 -> 5 -> 3 -> 1 -> 0 -> 2 -> 4 -> 6 -> null
7 -> 5 -> 3 -> 1 -> 0 -> 2 -> 4 -> 6 -> 8 -> null
9 -> 7 -> 5 -> 3 -> 1 -> 0 -> 2 -> 4 -> 6 -> 8 -> null
In this demonstrative program even numbers are inserted in the end of the list using the function push_back and odd numbers are inserted in the beginning of the list using the function push_front.
If you C compiler does not support designated initializers then this declaration
List list = { .head = NULL, .tail = NULL };
can be changed the following way
List list = { NULL, NULL };
The problem is that your code is appending the node to the front of the list in both cases. If you want to always append to the end of the list, you need to walk the list until the end and then add temp there.
I wrote this code off-the-cuff, so take it as pseudo-code:
// Assuming this function returns the front (head) of the list.
list* append_element_to_list(list* a, int b)
{
list *newNode;
newNode = (list*)malloc(sizeof(list*));
newNode->data = b;
// Handle the case where `a` is NULL. This means
// no list was passed in, so the newly created node
// will be returned to start the list.
if (a == NULL)
{
return newNode;
}
// If we get this far, it means `a` contains at least
// one node. So walk the list until the end.
list *currentNode = a;
while (currentNode->next != NULL)
{
currentNode = currentNode->next;
}
// Once you reach the end of the list, set
// `newNode` as the last node.
currentNode->next = newNode;
// The front of the list hasn't changed, so return that.
return a;
}
You have some mistakes in your code, I am making correction in your code, just changing what required.
first I want to focus on main issue, before inserting at last of any list, you should iterate the complete list.
i = a; // to iterate
while(i->next != NULL)
{
i = i->next;
}
// Now i is last node of list a
i->next = temp;
Now the below code, I just check it on TurboC, I am using your function and inserting three values and then printing the list.
Please see all the line comments:
#include <stdio.h>
#include <malloc.h>
typedef struct node{
int data;
struct node *next;
}list;
list* add_int_list(list* a,int b)
{
list *temp;
list *i;
temp = (list*)malloc(sizeof(list*));
temp->next = NULL;
temp->data = b;
if (a == NULL)//insert to the first node
{
//temp->data = b; - done above
//temp->next = a; no reason for this line
a = temp;
}
else
{
// temp->data = b; - done above
//temp->next = a; wrong logic
// a = temp;//I think the problem is here, couldnt find how to fix : Yes it is also wrong
//Here it required to iterate complete list and go to end
i = a; // to iterate
while(i->next != NULL)
{
i = i->next;
}
// Now i is last node of list a
i->next = temp;
}
return a;
}
void printList(list *root)
{
list *i;
if(root == NULL)
{
printf("List is empty");
}
else
{
i = root;
while(i != NULL){
printf("%d,",i->data);
i = i->next;
}
}
}
int main()
{
list *root = NULL;
clrscr();
root = add_int_list(root, 3);
root = add_int_list(root, 4);
root = add_int_list(root, 5);
printList(root);
return 0;
}
Related
I have an assignment to do.. the task is to delete only the first occurrence of an odd value in a doubly linked list, and I have to take in consideration all the special cases such as: if odd # beginning, middle or last. so far, my code works fine i checked it out, its work with deleting the front only (if its odd), but in the other cases such as deleting the last/ middle.. I couldn't manage to get an output for them. basically the running command shows me nothing :(
int DeleteFirstODD(Node **front) {
int oddnum;
Node *temp = *front;
if (*front == NULL) //Checking if the list is empty
return;
while (temp != NULL && temp->data % 2 == 0)
temp = temp->next;
if (temp == NULL)
return -1;
else if (temp == *front) { //if odd num founded # the begining of the doubly linked list!
oddnum = (*front)->data;
*front = (*front)->next;
(*front)->previous = NULL;
free(temp);
}
else if (temp->next == NULL) { //if odd num founded # the end
oddnum = temp->data;
temp->previous->next = NULL;
free(temp);
}
else { // if the odd somewhere in the middle
temp->previous->next = temp->next;
temp->next->previous = temp->previous;
oddnum = temp->data;
free(temp);
}
return oddnum;
}
my code works fine i checked it out, its work with deleting the front
only
You are wrong. This code snippet
else if (temp == *front) { //if odd num founded # the begining of the doubly linked list!
oddnum = (*front)->data;
*front = (*front)->next;
(*front)->previous = NULL;
free(temp);
}
can invoke undefined behavior when the list contains only one node because after this statement
*front = (*front)->next;
the pointer front will be equal to NULL and you may not use this null pointer in the following statement
(*front)->previous = NULL;
The function can be defined the following way. I suppose that if such a node with an odd value is found when the stored value is returned. Otherwise -1 is returned.
int DeleteFirstODD( Node **front )
{
int oddnum = -1;
Node *temp = *front;
while ( temp != NULL && temp->data % 2 == 0 )
{
temp = temp->next;
}
if ( temp != NULL )
{
oddnum = temp->data;
if ( temp == *front )
{
if ( temp->next != NULL )
{
temp->next->previous = temp->previous;
}
*front = temp->next;
}
else if ( temp->next == NULL )
{
temp->previous->next = temp->next;
}
else
{
temp->previous->next = temp->next;
temp->next->previous = temp->previous;
}
free( temp );
}
return oddnum;
}
Here is a demonstrative program.
#include <stdio.h>
#include <stdlib.h>
typedef struct Node
{
int data;
struct Node *next;
struct Node *previous;
} Node;
int push_front( Node **head, int data )
{
Node *new_node = malloc( sizeof( Node ) );
int success = new_node != NULL;
if ( success )
{
new_node->data = data;
new_node->next = *head;
if ( *head ) ( *head )->previous = new_node;
new_node->previous = NULL;
*head = new_node;
}
return success;
}
void display( const Node *head )
{
for ( ; head; head= head->next )
{
printf( "%d -> ", head->data );
}
puts( "null" );
}
int DeleteFirstODD( Node **front )
{
int oddnum = -1;
Node *temp = *front;
while ( temp != NULL && temp->data % 2 == 0 )
{
temp = temp->next;
}
if ( temp != NULL )
{
oddnum = temp->data;
if ( temp == *front )
{
if ( temp->next != NULL )
{
temp->next->previous = temp->previous;
}
*front = temp->next;
}
else if ( temp->next == NULL )
{
temp->previous->next = temp->next;
}
else
{
temp->previous->next = temp->next;
temp->next->previous = temp->previous;
}
free( temp );
}
return oddnum;
}
int main(void)
{
Node *head = NULL;
const int N = 10;
for ( int i = N; i != 0; i-- )
{
push_front( &head, i );
}
display( head );
for ( int num; ( num = DeleteFirstODD( &head ) ) != -1; )
{
printf( "The value of the deleted node is %d\n", num );
display( head );
}
return 0;
}
The program output is
1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9 -> 10 -> null
The value of the deleted node is 1
2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9 -> 10 -> null
The value of the deleted node is 3
2 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9 -> 10 -> null
The value of the deleted node is 5
2 -> 4 -> 6 -> 7 -> 8 -> 9 -> 10 -> null
The value of the deleted node is 7
2 -> 4 -> 6 -> 8 -> 9 -> 10 -> null
The value of the deleted node is 9
2 -> 4 -> 6 -> 8 -> 10 -> null
I am trying to write a function, which is deleting a specific element from my linked list, but it crash with segmentation fault when I reach the element.
Here is a part of my code
typedef struct dlist_t {
int data;
struct dlist_t *prev, *next;
} dlist_t;
typedef struct list_t {
dlist_t *head, *tail;
} list_t;
int delElement(list_t *list, int elem) {
while (list) {
if ((list->head)->data == elem) {
list->head->next = list->head->prev;
list->head->prev = list->head->next;
free(list);
return 1;
}
list = list->head->next;
}
return 0;
}
Your function definition does not make sense. For example in this assignment statement
list = list->head->next;
there are used objects of different types in the left hand side of the assignment (the type is list_t) and in the right hand side of the assignment (the type is dlist_t).
Or this call
free(list);
tries to free the list instead of only its one node. And so on.
The function can look the following way as it is shown in thje demonstrative program below.
#include <stdio.h>
#include <stdlib.h>
typedef struct dlist_t
{
int data;
struct dlist_t *prev, *next;
} dlist_t;
typedef struct list_t
{
dlist_t *head, *tail;
} list_t;
int delElement( list_t* list, int elem )
{
dlist_t **current = &list->head;
while ( *current != NULL && ( *current )->data != elem )
{
current = &( *current )->next;
}
int success = *current != NULL;
if ( success )
{
dlist_t *tmp = *current;
if ( ( *current )->next != NULL )
{
( *current )->next->prev = ( *current )->prev;
}
else
{
list->tail = ( *current )->prev;
}
*current = ( *current )->next;
free( tmp );
}
return success;
}
int pushFront( list_t *list, int elem )
{
dlist_t *new_node = malloc( sizeof( dlist_t ) );
int success = new_node != NULL;
if ( success )
{
new_node->next = list->head;
new_node->prev = NULL;
new_node->data = elem;
if ( list->head != NULL )
{
list->head->prev = new_node;
}
else
{
list->tail = new_node;
}
list->head = new_node;
}
return success;
}
int pushBack( list_t *list, int elem )
{
dlist_t *new_node = malloc( sizeof( dlist_t ) );
int success = new_node != NULL;
if ( success )
{
new_node->prev = list->tail;
new_node->next = NULL;
new_node->data = elem;
if ( list->tail != NULL )
{
list->tail->next = new_node;
}
else
{
list->head = new_node;
}
list->tail = new_node;
}
return success;
}
void printList( list_t *list )
{
for ( dlist_t *current = list->head; current != NULL; current = current->next )
{
printf( "%d -> ", current->data );
}
puts( "null" );
}
void printReverseList( list_t *list )
{
for ( dlist_t *current = list->tail; current != NULL; current = current->prev )
{
printf( "%d -> ", current->data );
}
puts( "null" );
}
int main(void)
{
list_t list = { .head = NULL, .tail = NULL };
const int N = 10;
for ( int i = 0; i < N; i++ )
{
if ( i % 2 == 0 ) pushFront( &list, N / 2 - i / 2 - 1 );
else pushBack( &list, N / 2 + i / 2 );
}
printList( &list );
printReverseList( &list );
putchar( '\n' );
for ( size_t i = 0; i < N; i++ )
{
if ( i % 2 == 0 ) delElement( &list, i / 2 );
else delElement( &list, N - i / 2 - 1 );
printList( &list );
printReverseList( &list );
putchar( '\n' );
}
return 0;
}
The program output is
0 -> 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9 -> null
9 -> 8 -> 7 -> 6 -> 5 -> 4 -> 3 -> 2 -> 1 -> 0 -> null
1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9 -> null
9 -> 8 -> 7 -> 6 -> 5 -> 4 -> 3 -> 2 -> 1 -> null
1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> null
8 -> 7 -> 6 -> 5 -> 4 -> 3 -> 2 -> 1 -> null
2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> null
8 -> 7 -> 6 -> 5 -> 4 -> 3 -> 2 -> null
2 -> 3 -> 4 -> 5 -> 6 -> 7 -> null
7 -> 6 -> 5 -> 4 -> 3 -> 2 -> null
3 -> 4 -> 5 -> 6 -> 7 -> null
7 -> 6 -> 5 -> 4 -> 3 -> null
3 -> 4 -> 5 -> 6 -> null
6 -> 5 -> 4 -> 3 -> null
4 -> 5 -> 6 -> null
6 -> 5 -> 4 -> null
4 -> 5 -> null
5 -> 4 -> null
5 -> null
5 -> null
null
null
Play with the program and playing investigate it.
Do not forget to write yourself the function that frees all allocated nodes in the list.
Im not too sure what causes your crash yet, but here i have a sample of code that should work.
Struct definition:
typedef int item_type;
typedef struct _list* list;
struct node {
item_type data;
struct node *next,*prev;
};
struct _list {
struct node* head;
struct node* tail;
int size;
};
Function for "element" deletion
void list_del(list l,item_type data) {
if (list->size ==0) {
abort();
}
int i=0;
struct node* head = l->head;
while(i<list->size){
if(head->data==data){
head->prev = head->next;
l->size -= 1;
free(head);
return;
}else{
head=head->next;
}
}
}
"item_type" it's a typedef, if you have lots of functions and you shouldn't care much about types. In our example is as you wanted type int
don't worry just try this code out.This is simplest of implementation and deletion a node in linked list and still if you face any issue feel free to ask .
#include <stdio.h>
#include <stdlib.h>
struct Node
{
int data;
struct Node *next;
}*first=NULL;
void create(int A[],int n)
{
int i;
struct Node *t,*last;
first=(struct Node *)malloc(sizeof(struct Node));
first->data=A[0];
first->next=NULL;
last=first;
for(i=1;i<n;i++)
{
t=(struct Node*)malloc(sizeof(struct Node));
t->data=A[i];
t->next=NULL;
last->next=t;
last=t;
}
}
void Display(struct Node *p)
{
while(p!=NULL)
{
printf("%d ",p->data);
p=p->next;
}
}
void RDisplay(struct Node *p)
{
if(p!=NULL)
{
RDisplay(p->next);
printf("%d ",p->data);
}
}
int Delete(struct Node *p,int index)
{
struct Node *q=NULL;
int x=-1,i;
if(index < 1 || index > count(p))
return -1;
if(index==1)
{
q=first;
x=first->data;
first=first->next;
free(q);
return x;
}
else
{
for(i=0;i<index-1;i++)
{
q=p;
p=p->next;
}
q->next=p->next;
x=p->data;
free(p);
return x;
}
}
int main()
{
int A[]={10,20,30,40,50};
create(A,5);
printf(“%d\n",Delete(first),2);
Display(first);
return 0;
}
So first we have created the linked list using malloc function . We have created a structure with variable which will build linked list i.e "data" and also created the pointer of struct type .
Then we have created a function name "create" to create our first node .And inserted the value according to it .
Then as you can see we g=have used for loop to fasten the process of creating the link list till the value of n.
Then for displaying the linked list we have created the function name "Display"
and if p!=NULL i.e node last column which contain address we have print the values/data of that node using for loop.
Then for deletion we have used function name "Delete" :
1st step: Is we need a pointer "p" that will point on first node .
2nd step: Now move first to next node.
3rd step: Now store the value of deleted node in new variable "x".
4th step: Delete p
The remaining code is for deleting the node from the specific position by using the two pointer, one pointer for previous node and next pointer for current node.
Just try this out or cross check with your code where you are going wrong .
I've been working for a school project and come across this issue.
I'm trying to store the list with malloc but this piece of code doesn't seem to work.
column_t *sorted_insert(column_t *lst, char col3[MAX_SIZE], long int rep){
if (!lst || rep < lst->rep)
{
column_t *new = (column_t*) malloc(sizeof(column_t));
strcpy(new->col3, col3);
new->rep = rep;
new->next = lst;
new->previous = NULL;
lst = new;
if (lst->next)
lst->next->previous = new;
}else
{
lst->next = sorted_insert(lst->next,col3,rep);
lst->next->previous = lst;
}
return lst;
}
Tried to call the function:
sorted_insert(lst,"Test",0);
printf("%s",lst->col3);
And as no output. The program just closes.
UPDATE #Vlad from Moscow
column_t *sorted_insert(column_t *lst, char col3[MAX_SIZE], long int rep){
if (lst == NULL|| rep < lst->rep)
{
column_t *new = malloc(sizeof(column_t));
if (new != NULL)
{
strcpy(new->col3, col3);
new->rep = rep;
new->previous = NULL;
new->next = lst;
if (lst != NULL)
lst->previous = new;
}
lst = new;
}else
{
column_t *new = sorted_insert(lst->next, col3, rep);
if (new != NULL)
{
lst->next = new;
new->previous = lst;
}
}
return lst;
}
Changed the call to:
lst = sorted_insert(lst,tmp->col3,w);
display(lst);
Output:
Output of the list is correct now but not sorted by ascending order..
It seems that the problem is in how you are calling the function.
The call should look like
column_t *lst = NULL;
lst = sorted_insert(lst,"Test",0);
Here is a simplified demonstrative program that uses your function sorted_insert with minor changes and excluding the data member of the character array type.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
struct Node
{
int data;
struct Node *prev;
struct Node *next;
};
struct Node * sorted_insert( struct Node *head, int data )
{
if ( head == NULL || data < head->data )
{
struct Node *new_node = malloc( sizeof( struct Node ) );
if ( new_node != NULL )
{
new_node->data = data;
new_node->prev = NULL;
new_node->next = head;
if ( head != NULL ) head->prev = new_node;
}
head = new_node;
}
else
{
struct Node *new_node = sorted_insert( head->next, data );
if ( new_node != NULL )
{
head->next = new_node;
new_node->prev = head;
}
}
return head;
}
void display( struct Node *head )
{
for ( ; head != NULL; head = head->next )
{
printf( "%d -> ", head->data );
}
puts( "null" );
}
int main(void)
{
struct Node *head = NULL;
const size_t N = 10;
srand( ( unsigned int )time( NULL ) );
for ( size_t i = 0; i < N; i++ )
{
head = sorted_insert( head, rand() % N );
display( head );
}
return 0;
}
Its output might look like
8 -> null
3 -> 8 -> null
3 -> 8 -> 9 -> null
1 -> 3 -> 8 -> 9 -> null
1 -> 1 -> 3 -> 8 -> 9 -> null
1 -> 1 -> 3 -> 6 -> 8 -> 9 -> null
1 -> 1 -> 3 -> 3 -> 6 -> 8 -> 9 -> null
1 -> 1 -> 3 -> 3 -> 4 -> 6 -> 8 -> 9 -> null
1 -> 1 -> 3 -> 3 -> 4 -> 5 -> 6 -> 8 -> 9 -> null
1 -> 1 -> 3 -> 3 -> 4 -> 5 -> 6 -> 8 -> 9 -> 9 -> null
Caveat: Since it seems you're still having some trouble even with Vlad's answer, I've come up with a refactored version [that may or may not be what you wanted].
I'm using two lists. Append raw input strings to first list, but just bump the count if it's a dup of an existing list entry.
So, now we have a list that has the a single item for each unique string and its frequency/repetition count.
Then, move the entries into a second list, sorting by insertion based on the frequency.
So, here's the code. As I mentioned in my comments, the recursive solution doesn't scale, and, further, is slower. At the least, this may help you adapt your version. YMMV ...
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_SIZE 16
typedef struct column column_t;
struct column {
column_t *next;
column_t *prev;
long rep;
char col3[MAX_SIZE];
};
column_t *
newnode(char *col3)
{
column_t *new = malloc(sizeof(column_t));
strcpy(new->col3,col3);
new->prev = NULL;
new->next = NULL;
new->rep = 1;
return new;
}
// addnode -- add string to basic list
column_t *
addnode(column_t *head,char *col3)
{
column_t *cur;
column_t *prev;
column_t *new;
do {
// add to empty list
if (head == NULL) {
new = newnode(col3);
head = new;
break;
}
// find matching node for string
prev = NULL;
for (cur = head; cur != NULL; cur = cur->next) {
if (strcmp(cur->col3,col3) == 0)
break;
prev = cur;
}
// increment count on existing node
if (cur != NULL) {
cur->rep += 1;
break;
}
// append to tail of list
new = newnode(col3);
prev->next = new;
new->prev = prev;
} while (0);
return head;
}
column_t *
sorted_insert(column_t *head,column_t *new)
{
column_t *cur;
column_t *prev;
do {
new->next = NULL;
new->prev = NULL;
// add to empty list
if (head == NULL) {
head = new;
break;
}
// find next higher node count
prev = NULL;
for (cur = head; cur != NULL; cur = cur->next) {
if (cur->rep > new->rep)
break;
prev = cur;
}
// insert before a node that is higher
if (cur != NULL) {
prev = cur->prev;
if (prev != NULL)
prev->next = new;
new->prev = prev;
new->next = cur;
// inserting before the head of the list
if (cur == head)
head = new;
break;
}
// new node is higher than all -- append to tail of list
new->prev = prev;
if (prev != NULL)
prev->next = new;
} while (0);
return head;
}
void
listprint(column_t *head,const char *tag)
{
column_t *cur;
for (cur = head; cur != NULL; cur = cur->next)
printf("%s %s - %ld\n",tag,cur->col3,cur->rep);
}
int
main(void)
{
column_t *orig = NULL;
char *input[] = {
"DA", "DA",
"JL",
"FF",
"JD",
"FF",
"PQ", "QP",
"QP", "QP", "QP",
NULL
};
for (char **str = input; *str != NULL; ++str)
orig = addnode(orig,*str);
listprint(orig,"ORIG");
column_t *sorted = NULL;
column_t *next;
for (; orig != NULL; orig = next) {
next = orig->next;
sorted = sorted_insert(sorted,orig);
}
listprint(sorted,"SORT");
return 0;
}
I have this piece of code, it deletes the last element from a linked list. What changes do I have to make so it will delete the last TWO elements of the linked list?
void deletesEnd() {
struct node *temp, *last;
temp = head;
last = temp;
while (temp != NULL && temp->next != NULL) {
last = temp;
temp = temp->next;
}
if (last == temp) {
free(temp);
head = NULL;
} else {
free(last->next);
last->next = NULL;
}
}
The simplest solution to remove the last 2 elements of the list is to call deletesEnd() twice. Note that deletesEnd() should take head as an argument and return the new value. You would delete the last 2 by issuing a nested call:
struct node *deletesEnd(struct node *head) {
struct node *temp, *last;
last = temp = head;
while (temp && temp->next != NULL) {
last = temp;
temp = temp->next;
}
if (last == head) {
free(head);
head = NULL;
} else {
free(last->next);
last->next = NULL;
}
return head;
}
Delete the last element: head = deletesEnd(head);
Delete the last 2 elements: head = deletesEnd(deletesEnd(head));
The simplicity of the design more than compensates for the overhead of enumerating the list twice.
If you absolutely want a specific function, you can extend your approach this way:
struct node *deleteLast2Nodes(struct node *head) {
struct node *temp, *last;
last = temp = head;
while (temp && temp->next != NULL && temp->next->next != NULL) {
last = temp;
temp = temp->next;
}
if (last == head) {
if (head) {
free(head->next);
}
free(head);
head = NULL;
} else {
free(last->next->next);
free(last->next);
last->next = NULL;
}
return head;
}
Here is a demonstrative program that shows how two last nodes can be deleted simultaneously. In fact the function is similar to your function except it checks not only the next node but also the next->next node.
#include <stdio.h>
#include <stdlib.h>
struct node
{
int value;
struct node *next;
} *head;
void push( int value )
{
struct node *tmp = malloc( sizeof( struct node ) );
tmp->value = value;
tmp->next = head;
head = tmp;
}
void display()
{
for ( struct node *current = head; current; current = current->next )
{
printf( "%d ", current->value );
}
}
void deleteLastTwo()
{
struct node *current = head;
struct node *prev = head;
if ( current && current->next )
{
while ( current->next->next )
{
prev = current;
current = current->next;
}
}
if ( current )
{
if ( current->next )
{
free( current->next );
}
if ( prev == current )
{
head = NULL;
}
else
{
prev->next = NULL;
}
free( current );
}
}
int main(void)
{
const int N = 11;
for ( int i = N; i != 0; i-- ) push( i - 1 );
display();
printf( "\n" );
while ( head )
{
deleteLastTwo();
display();
printf( "\n" );
}
return 0;
}
The program output is
0 1 2 3 4 5 6 7 8 9 10
0 1 2 3 4 5 6 7 8
0 1 2 3 4 5 6
0 1 2 3 4
0 1 2
0
Take into account that it is not a good idea when the head node is declared like a global variable. It is better when it can be declared like a local variable. In this case you will need to rewrite the methods of the list because in most cases the current methods will not work correctly.
This logic will delete your last 2 node in singly linked list.
void deletesEnd()
{
struct node *temp, *last;
temp = head;
last = temp;
while (temp->next->next != NULL)
{
last = temp->next;
if(last->next->next!=NULL)
temp = temp->next;
else
break;
}
struct node *ptr=last->next;
last->next=ptr->next;
free(ptr);
temp->next=last->next;
free(last);
}
For fun & education: simple recursive version.
The function return := the number of nodes below us
After the recursion returns, we can decide if we are too close to the tail.
and remove ourselves
because we pass a pointer to pointer, this should also work for lists of size=2 and smaller
unsigned del_tail_n(struct llist **pp, unsigned nn)
{
unsigned pos;
if (!*pp) return 0;
// this recursive call returns 0 iff (*pp)->next is NULL
pos = del_tail_n( &(*pp)->next, nn);
if (pos < nn) {
// free (*pp);
*pp = NULL;
}
return 1+pos;
}
For those who don't like recursion, here is a non-recursive version.
[do note that both versions work for empty lists (*pp == NULL) , or for lists smaller than nn ]
void del_tail_n2(struct llist **pp, unsigned nn)
{
struct llist *p;
/* Advance p pointer n positions down, starting from *pp. */
for (p= *pp; p; p=p->next) {
if (nn-- < 1) break;
}
/* Do a synchronous walk down for both p and *pp, until p is NULL. */
for ( ; p; p=p->next) {
pp = &(*pp)->next;
}
/* Now, *pp is the first node to delete
** Delete it and everything below it.
*/
for ( ;(p = *pp); ){
*pp = p->next;
// free (p);
}
return;
}
I'm trying get the method shiftInsert to work. I want to insert a number into the list and make the last number disappear. If this is the list p 1 -> 2 -> 3 -> 4 -> 5, after shiftInsert(8) the list needs to look like this p 8 -> 1 -> 2 -> 3 -> 4. As you can see the last number needs to disappear. How do I implement this?
#include <stdio.h>
#include <stdlib.h>
struct elem {
int value;
struct elem *next;
};
typedef struct elem Node;
Node *root;
Node * addElem(Node *p, int value) {
p->next = malloc(sizeof *p);
p = p->next;
p->value = value;
p->next = NULL;
return p;
}
void shiftInsert(Node *n, int v) {
int tmp;
while (n != NULL) {
Node * new_node;
new_node = malloc(sizeof (new_node));
n = n->next;
}
}
void printList() {
Node *p = root;
while (p != NULL) {
printf("%2d -> ", p->value);
p = p->next;
}
printf("NULL\n");
}
int main(int argc, char **argv) {
Node *p;
int i = 0;
root = p = malloc(sizeof (Node));
p->value = 1;
for (i = 2; i <= 10; i++) {
p = addElem(p, i);
}
printList();
shiftInsert(root, 88);
printList();
shiftInsert(root->next->next->next, 33);
printList();
return 0;
}
According to your example, you want to insert into the first position and remove the last one. So basically you want to create a new root then find the last but one element and set its next to NULL.
So first the delete function:
void deleteLast()
{
int i, before_last = 0;
Node *temp;
/* Find last element to remove it*/
temp = root;
for(i = 0; temp->next != NULL; i++) { // "i" will be the index of the last element
temp = temp->next;
}
before_last = i - 1; // the one before "i" will be the new last element
temp = root;
for(i = 0; i < before_last; i++) { // find the one before last and set its "next" NULL
temp = temp->next;
}
free(temp->next);
temp->next = NULL;
}
New root, create an element which will be the new root. Set its next to root, then make the new element as the root.
void shiftInsertRoot(int v) {
if (root != NULL) {
Node * new_root;
/* Create new root */
new_root = malloc(sizeof (new_root));
new_root->next = root; // save previous root
new_root->value = v; // set new value
root = new_root; // update root pointer
deleteLast();
}
}
According to your main, you want to insert after a certain element, you have to find it first. Then create a new element and set its next to the next of the original element, so you won't lose the rest of the list. Finally set the next of the original element to the new element.
void shiftInsertAnywhere(Node *position, int v) {
int i;
Node *temp;
temp = root;
for(i = 0; temp->value != position->value; i++) {
temp = temp->next;
}
if (temp != NULL) {
Node * new_root;
/* Create new root */
new_root = malloc(sizeof (new_root));
new_root->next = temp->next; // save the rest of the list
new_root->value = v; // set new value
position->next = new_root; // insert the new element after "position" element
deleteLast();
}
}
This will insert after the position.
Example:
printList();
shiftInsertRoot(88);
printList();
shiftInsertRoot(33);
printList();
shiftInsertAnywhere(root->next->next, 99);
printList();
shiftInsertAnywhere(root, 17171);
printList();
Output:
You don't need to allocate new space to insert nodes without growing the list. Here is a function that inserts a node at the head of the list, and drops the last node:
Node * shiftInsert(Node *n, int v) {
Node *tail = n;
if (n == NULL){
return n;
} else if (n->next == NULL) {
n->value = v;
return n;
}
while (tail->next->next != NULL)
tail = tail->next;
tail->next->value = v;
tail->next->next = n;
n = tail->next;
tail->next = NULL;
return n;
}
Notice that this version of shiftInsert() returns a pointer to the head of the list.
Here is a second function that allows you to insert a node anywhere in the list, and drops the last node:
Node * shiftInsertAny(Node *root, Node *n, int v) {
Node *tail = n;
Node *insert = root;
if (root == NULL){
return root;
} else if (root->next == NULL) {
root->value = v;
return root;
}
while (n != root && insert->next != n)
insert = insert->next;
if (insert->next->next == NULL) {
insert->next->value = v;
return root;
}
while (tail->next->next != NULL)
tail = tail->next;
tail->next->value = v;
tail->next->next = n;
if (insert == root)
root = tail->next;
else
insert->next = tail->next;
tail->next = NULL;
return root;
}
This function also returns a pointer to the head of the list, and takes both a pointer to the head of the list, and a pointer to the insertion point as arguments. The new node is inserted in front of the node indicated by the pointer n.
If you call these functions like this in your code:
printList();
root = shiftInsert(root, 88);
printList();
root = shiftInsertAny(root, root->next->next->next, 33);
printList();
this is the output:
1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9 -> 10 -> NULL
88 -> 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9 -> NULL
88 -> 1 -> 2 -> 33 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> NULL
I updated the above code snippet for the shiftInsertAny() function. I had made a change to allow it to insert a node at the head of the list, but I forgot to edit the code snippet earlier. With this function you can insert into the first node or the last node. For example, with a 5-element list, you can do:
printList();
root = shiftInsertAny(root, root, 88);
printList();
root = shiftInsertAny(root, root->next->next->next->next, 33);
printList();
which has output:
1 -> 2 -> 3 -> 4 -> 5 -> NULL
88 -> 1 -> 2 -> 3 -> 4 -> NULL
88 -> 1 -> 2 -> 3 -> 33 -> NULL