swap in doubly linked list - c

I am trying to swap two nodes in a doubly linked list. Below is the part of program having swap function.
int swap (int x, int y)
{
struct node *temp = NULL ;
struct node *ptr1, *ptr2;
temp = (struct node *)malloc(sizeof(struct node));
if (head == NULL )
{
printf("Null Nodes");
}
else
{
ptr1 = ptr2 = head;
int count = 1;
while (count != x)
{
ptr1 = ptr1->next;
count++;
}
int count2 = 1;
while (count2 != y)
{
ptr2 = ptr2->next;
count2++;
}
ptr1->next->prev = ptr2;
ptr1->prev->next = ptr2;
ptr2->next->prev = ptr1;
ptr2->prev->next = ptr1;
temp->prev = ptr1->prev;
ptr1->prev = ptr2->prev;
ptr2->prev = temp->prev;
temp->next = ptr1->next;
ptr1->next = ptr2->next;
ptr2->next = temp->next;
}
return 0;
}
When I run this program, in case of 1st and 2nd node, it crashes. while in case of any other nodes, it gives infinite loop output. (eg:- 2->4 2->4 2->4....so on)`.
I know there are some more questions about node swappings, but I didn't find any one similar to my problem. Please help me out..!!
Thanks in Advance.

The code will fail if ptr1 == head (ptr1->prev == NULL) or ptr2 == head (ptr2->prev == NULL), because it ends up trying to use head->next, which doesn't exist. There also needs to be a check for the end of a list, if ptr1->next == NULL or ptr2->next == NULL, which can be handled using a local tail pointer. Using pointers to pointer to node can simplify the code. For example the pointer to next pointer to ptr1 could be &ptr1->prev->next or &head. The pointer to prev pointer to ptr2 could be &ptr2->next->prev or &tail (and set tail = ptr2).
Using pointers to pointer to node fixes the issue with swapping adjacent nodes. Also temp can be a pointer to node.
Example code using pointers to nodes (instead of counts) to swap:
typedef struct node NODE;
/* ... */
NODE * SwapNodes(NODE *head, NODE *ptr1, NODE *ptr2)
{
NODE **p1pn; /* & ptr1->prev->next */
NODE **p1np; /* & ptr1->next->prev */
NODE **p2pn; /* & b->prev->next */
NODE **p2np; /* & b->next->prev */
NODE *tail; /* only used when x->next == NULL */
NODE *temp; /* temp */
if(head == NULL || ptr1 == NULL || ptr2 == NULL || ptr1 == ptr2)
return head;
if(head == ptr1)
p1pn = &head;
else
p1pn = &ptr1->prev->next;
if(head == ptr2)
p2pn = &head;
else
p2pn = &ptr2->prev->next;
if(ptr1->next == NULL){
p1np = &tail;
tail = ptr1;
} else
p1np = &ptr1->next->prev;
if(ptr2->next == NULL){
p2np = &tail;
tail = ptr2;
}else
p2np = &ptr2->next->prev;
*p1pn = ptr2;
*p1np = ptr2;
*p2pn = ptr1;
*p2np = ptr1;
temp = ptr1->prev;
ptr1->prev = ptr2->prev;
ptr2->prev = temp;
temp = ptr1->next;
ptr1->next = ptr2->next;
ptr2->next = temp;
return head;
}

This can be compacted, but if you are having problems, it can help to spell it out in detail.
typedef struct node Node;
void link( Node* a, Node* b )
{
a->next = b;
b->prev = a;
}
void swap_nodes( Node* a, Node* b )
{
if(a==b) return; // don't swap with yourself
// handle adjacent nodes separately
if( a->next == b )
{
Node* bef = a->prev;
Node* aft = b->next;
link( bef, b); // link bef, b, a, aft
link( b, a );
link( a, aft );
}
else if( b->next == a )
{
Node* bef = b->prev;
Node* aft = a->next;
link( bef, a); // link bef, a, b, aft
link( a, b );
link( b, aft );
}
else
{
Node* a_prv = a->prev;
Node* a_nxt = a->next;
Node* b_prv = b->prev;
Node* b_nxt = b->next;
link( a_prv, b ); link( b, a_nxt ); // links b in a's old position
link( b_prv, a ); link( a, b_nxt ); // links a in b's old position
}
}
Also note that your head node should never be null, it should be a sentry node that links to itself if your list is empty. This means that there are never a first node, nor a last, nor is the list ever empty. This removes a ton of special cases. See here

Related

Removing node from doubly linked list gives segmentation fault - C

I have written a program that can can add char characters to the start of a doubly linked list. Now once I have this list, the aim of my program is to remove certain char character(s) from the list entirely. For example (using curly brackets only for representative purposes): if list consists of { a, b, b, a, c }, then my program can remove all "b" from the list to make it { a, a, c}. Moreover, if my list is {b, a, c, a} or {a, c, a, b} and if I want to remove "b" then the program works fine for both cases and gives me {a, c, a}.
But there's a number of issues (for all cases assume I want to remove "b"):
if my list is {b, a, b, a, c} ("b" at front and somewhere in middle), I get segmentation fault (I think it has to do with using cursor in the while loop, but I don't know why exactly and how to fix it)
if my list is {a, b, b, a, c, b} ("b" in middle and at last) then output gives me weird symbols (I'm assuming its a memory fault, don't know why)
Here is the code I am using:
#include<stdio.h>
#include<stdlib.h>
struct list
{
int data;
struct list* next;
struct list* prev;
};
struct list* head; // global variable - pointer to head node of list.
struct list* last; // global variable - pointer to last node of list
//Creates a new list and returns pointer to it.
struct list* GetNewNode(char x)
{
struct list* newNode
= malloc(sizeof(struct list));
newNode->data = x;
newNode->prev = NULL;
newNode->next = NULL;
return newNode;
}
//Inserts a list at head of doubly linked list
void InsertAtHead(char x)
{
struct list* newNode = GetNewNode(x);
if(head == NULL)
{
head = newNode;
return;
}
head->prev = newNode;
newNode->next = head;
head = newNode;
struct list* temp = head;
while (temp->next != NULL) temp = temp->next;
last = temp;
}
void remove_element (char character)
{
struct list * cursor, *previous, *store_el;
//int boolean = 0;
if (head == NULL) return;
else
{
cursor = head;
while(cursor != NULL)
{
if (cursor->data == character)
{
if (cursor->prev == NULL)
{
// printf("deleting from front\n");
previous = head;
head = head->next;
head->prev = NULL;
//boolean = 1;
//free(previous);
}
if (cursor->next == NULL)
{
//printf("deleting from back\n");
previous = last;
last = last->prev;
last->next = NULL;
//boolean = 1;
//free(previous);
}
else
{
// printf("deleting from middle\n");
previous = cursor;
cursor = cursor->next;
cursor->prev = previous->prev;
store_el = previous->prev;
store_el->next = cursor;
cursor = head;
}
free(previous);
//printf("head data = %c\n", cursor->data);
}
cursor = cursor->next;
}
}
}
//Prints all the elements in linked list in forward traversal order
void Print()
{
struct list* temp = head;
printf("Forward: ");
while(temp != NULL)
{
printf("%c ",temp->data);
temp = temp->next;
}
printf("\n");
}
int main()
{
char character;
/*Driver code to test the implementation*/
head = NULL; // empty list. set head as NULL.
// Calling an Insert and printing list before and after deletion of character
InsertAtHead('c');
InsertAtHead('a');
InsertAtHead('b');
InsertAtHead('b');
InsertAtHead('a');
Print();
printf("After deletion:\n");
remove_element ('b');
Print();
}
/*
*I changed the name of your variable 'last' to 'tail'
*I removed the code at the end of your InsertAtHead function
*I added "tail = newNode;"
*I changed the name of your variable 'previous' to 'garbage'
*I removed your variable 'store_el' completely.
*I could have changed the whole code in your remove element function because the 3 cases are unnecessary but anyway.
*/
//Inserts a list at head of doubly linked list
void InsertAtHead(char x){
struct list* newNode = GetNewNode(x);
if (head == NULL){
head = newNode;
tail = newNode;
return;
}
head->prev = newNode;
newNode->next = head;
head = newNode;
}
void remove_element (char character){
struct list * cursor, *garbage;
cursor = head;
while(cursor != NULL){
if (cursor->data == character){
garbage = cursor;
if (cursor->prev == NULL){
head = head->next;
If (head!=NULL) head->prev = NULL;
cursor=head;
}else if (cursor->next == NULL){
tail = tail->prev;
tail->next = NULL;
cursor=NULL;
}else{
garbage->prev->next = garbage->next;
garbage->next->prev = garbage->prev;
cursor=cursor->next;
}
free(garbage);
} else cursor=cursor->next;
}
}
Try it now.
The problem with your code was that you were using the memory you freed.
/*
*cursor and previous point to the same memory address
*you free the memory that the variable previous points so the cursor points to that freed memory
*when you save the next address to the cursor using that freed memory you create an undefined behaviour (your code may work or may not)
*/
cursor = head;
while(cursor != NULL)
{
if (cursor->data == character)
{
if (cursor->prev == NULL)
{
previous = head;
head = head->next;
head->prev = NULL;
free(previous);
...
cursor=cursor->next;
The Improved Code:
#include<stdio.h>
#include<stdlib.h>
//The type of your variable data was wrong. I changed it to char
struct list{
char data;
struct list *prev, *next
};
void remove_element (char character){
struct list * cursor, *garbage;
cursor = head;
while(cursor != NULL){
if (cursor->data == character){
garbage = cursor;
if (garbage->prev!=NULL ) garbage->prev->next = garbage->next;
if (garbage->next!=NULL ) garbage->next->prev = garbage->prev;
cursor=cursor->next;
if (head==garbage) head=cursor;
//Basically the tail variable has no use for your current program.
//if (tail==garbage) tail=garbage->prev;
free(garbage);
} else cursor=cursor->next;
}
}
Try to update the cursor
cursor = head;
after you delete from the front.
Ellothere I think the problem in your program is you are assigning the address of the node in previous but you are not freeing it side by side.
if (cursor->prev == NULL)
{
// printf("deleting from front\n");
previous = head;
head = head->next;
head->prev = NULL;
//boolean = 1;
//free(previous);
}
if (cursor->next == NULL)
{
//printf("deleting from back\n");
previous = last;
last = last->prev;
last->next = NULL;
//boolean = 1;
//free(previous);
}
Here you are storing node but freeing it at the end and then there are 2 if statements here then what is happening is both 'b' in {a b b a c} are next to each other so first previous variable is storing the address of first 'b' then it is storing the address of next 'b' and it is just freeing that 'b' and that one 'b' remains there . In short you should free the node side- by - side. I did this small change and it works fine .
if (cursor->prev == NULL)
{
// printf("deleting from front\n");
previous = head;
head = head->next;
head->prev = NULL;
free(previous);
//boolean = 1;
//free(previous);
}
if (cursor->next == NULL)
{
//printf("deleting from back\n");
previous = last;
last = last->prev;
last->next = NULL;
free(previous);
//boolean = 1;
//free(previous);
}
else
{
// printf("deleting from middle\n");
previous = cursor;
cursor = cursor->next;
cursor->prev = previous->prev;
store_el = previous->prev;
store_el->next = cursor;
cursor = head;
}
I have just added a free function in both if statements.

function swapNode does not work in doubly linked list

Function swapNode swaps 2 nodes in list. The function create node* temp to store temporary data then swaps the data of node* A and node* B. I can not understand why it does not work. Below here is my code:
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
struct node;
struct list;
typedef struct node node;
typedef struct list list;
struct node
{
int point;
char name[30];
node *next;
node *prev;
};
struct list
{
node *head;
node *tail;
int count;
};
node *allocateNewNode(int point, char name[30], node *prev, node *next);
list *createList();
bool insertHead(list *listNode, int point, char name[30]);
bool compareName(char a[30], char b[30]);
bool swapNode(list *listNode, char nameA[30], char nameB[30]);
int main()
{
list *listNode = createList();
insertHead(listNode, 10, "abc def");
insertHead(listNode, 9, "qwe rty");
insertHead(listNode, 8, "ui op");
insertHead(listNode, 30, "fgh jkl");
insertHead(listNode, 1234, "akaka");
swapNode(listNode, "ui op", "abc def");
node *temp = listNode->head;
while (temp != NULL)
{
printf("%-20s%d\n", temp->name, temp->point);
temp = temp->next;
}
free(temp);
printf("\n%d", listNode->count);
return 0;
}
node *allocateNewNode(int point, char name[30], node *prev, node *next)
{
node *newNode = (node *)malloc(sizeof(node));
newNode->point = point;
strcpy(newNode->name, name);
newNode->next = next;
newNode->prev = prev;
return newNode;
}
list *createList()
{
list *listNode = (list *)malloc(sizeof(list));
listNode->count = 0;
listNode->head = NULL;
listNode->tail = NULL;
return listNode;
}
bool insertHead(list *listNode, int point, char name[30])
{
node *newNode = allocateNewNode(point, name, NULL, listNode->head);
if (listNode->head)
listNode->head->prev = newNode;
listNode->head = newNode;
if (listNode->tail == NULL)
listNode->tail = newNode;
++listNode->count;
return true;
}
bool compareName(char a[30], char b[30])
{
for (int i = 0; i < 31; i++)
{
if (a[i] != b[i])
return false;
if (a[i] == '\0')
break;
}
return true;
}
bool swapNode(list *listNode, char nameA[30], char nameB[30])
{
node *A = NULL, *B = NULL;
node *temp = listNode->head;
for (int i = 0; i < listNode->count - 1; i++)
{
if (compareName(temp->name, nameA))
A = temp;
else if (compareName(temp->name, nameB))
B = temp;
temp = temp->next;
if (A || B)
break;
}
if (!A || !B)
return false;
else if (A == B)
return false;
*temp = *A;
*A = *B;
*B = *temp;
if (A->prev)
A->prev->next = A;
if (A->next)
A->next->prev = A;
if (A->prev)
A->prev->next = A;
if (A->next)
A->next->prev = A;
free(temp);
return true;
}
tks for your help
In swapNode, A and B are initially NULL. The loop that searches for the two matching nodes terminates early when either node is found:
if (A || B)
break;
At most one of A and B will be non-NULL when the loop terminates so at least one of A and B will be NULL. This causes the function to return false:
if (!A || !B)
return false;
To avoid that, you should change the loop to break when both A and B are non-NULL:
if (A && B)
break;
Also, the loop is only checking count - 1 elements of the list, so it ignores the final element:
for (int i = 0; i < listNode->count - 1; i++)
To check all elements, you need to change that to:
for (int i = 0; i < listNode->count; i++)
Alternatively, you could ignore listNode->count and check the temp pointer instead:
while (temp != NULL)
That will work because temp is initialized to listNode->head, which will be NULL for an empty list, and for a non-empty list, the next member of the final element on the list is NULL, so temp = temp->next; will set temp to NULL when the final element has been checked.
There are other problems in swapNode related to the actual swapping of the nodes after they have been found. The original code to do that looks totally wrong:
*temp = *A;
*A = *B;
*B = *temp;
The temp pointer will either be NULL or will point to a node after the A and B nodes.
if (A->prev)
A->prev->next = A;
if (A->next)
A->next->prev = A;
if (A->prev)
A->prev->next = A;
if (A->next)
A->next->prev = A;
The code does not alter listNode->head or listNode->tail when A or B is at the head or tail of the list.
free(temp);
Why is it freeing temp here when all the function is supposed to be doing is swapping nodes?
The code to swap the nodes A and B needs to be able to deal with neither, either or both nodes being at the end(s) of the list, and with A and B being adjacent nodes in either order. Here is a sequence to handle all that:
/* update list head pointer */
if (listNode->head == A)
listNode->head = B;
else if (listNode->head == B)
listNode->head = A;
/* update list tail pointer */
if (listNode->tail == A)
listNode->tail = B;
else if (listNode->tail == B)
listNode->tail = A;
/* update ->prev->next pointers */
if (A->prev != NULL && A->prev != B)
A->prev->next = B;
if (B->prev != NULL && B->prev != A)
B->prev->next = A;
/* update ->next->prev pointers */
if (A->next != NULL && A->next != B)
A->next->prev = B;
if (B->next != NULL && B->next != A)
B->next->prev = A;
/* update A->prev and B->prev pointers */
if (A->prev == B)
{
A->prev = B->prev;
B->prev = A;
}
else if (B->prev == A)
{
B->prev = A->prev;
A->prev = B;
}
else
{
temp = A->prev;
A->prev = B->prev;
B->prev = temp;
}
/* update A->next and B->next pointers */
if (A->next == B)
{
A->next = B->next;
B->next = A;
}
else if (B->next == A)
{
B->next = A->next;
A->next = B;
}
else
{
temp = A->next;
A->next = B->next;
B->next = temp;
}
Using a debugger you would see that function swapNode returns at
if (!A || !B)
return false;
If you would step through the for loop you could see that you break from the loop when at least one of A and B is set, i.e. when the first matching node is found.
if (A || B)
break;
Change this to
if (A && B)
break;

Double linked lists: swapping function doesn't always work

I have written this code and in general works good, but trying to run these particular lines in main, when we arrive to the point in which i == 74 the elements of the list are 4 - 11 - 18 - 4 - 10 - 18 - 17 - 22 - 14 - 29 and the swapNodes() function has to swap the two nodes with the keys 18, but instead I get these elements: 4 - 18 - 4 - 10 - 18 - 17 - 22 - 14 - 29. I tried to initialize the list with the exact values as before "swapping" and then try to swap these two nodes and everything works as it should.
PS: I would appreciate if someone could help me to write the swapNodes() function with fewer lines but that's not a necessity at this moment.
typedef struct _node{
int key;
struct _node *next;
struct _node *prev;
}node;
node* createNode(int key){
node* a = (node*)malloc(sizeof(struct _node));
a->key = key;
a->next = NULL;
a->prev = NULL;
return a;
}
void printList(node* head){
while (head != NULL){
printf("%d", head->key);
if(head->next != NULL) printf(" - ");
head = head->next;
}
printf("\n");
}
void fillList(node** head, int dim){
int i;
for(i=0; i<dim; i++)
listInsert(head, createNode(rand()%30));
}
//findes a node given an index, the indices start from 1
node** findNode(node** head, int index){
int i;
for(i=1; i<index; i++)
head = &(*head)->next;
if(head != NULL) return head;
else return NULL;
}
void listInsert(node** head, node* node){
if((*head) == NULL){
(*head) = node;
return;
}
node->next = (*head);
(*head)->prev = node;
(*head) = node;
}
int main(){
node* list = NULL;
fillList(&list, 10);
int i, a, b;
for(i=0; i<100; i++){
printList(list);
a = rand()%10 +1;
b = rand()%10 +1;
swapNodes(&list, *findNode(&list, a), *findNode(&list, b));
printList(list);
printf("\n");
}
return 0;
}
EDIT:
I managed to rewrite the swapNodes() function but this time executing the same lines in main I get a loop in the list for i==15, a==4 and b==2. Again if I try to manualy swap any of the nodes the function works fine.
void swapNodes(node** head, node* a, node* b){
node* aPrev = a->prev;
node* aNext = a->next;
node* bPrev = b->prev;
node* bNext = b->next;
if(a == b) return;
if(a->prev == b ||
(b->prev == NULL && a->next == NULL) ||
(b->prev == NULL && b->next == a) ||
a->next == NULL) return swapNodes(head, b, a);
if(a->prev == NULL)
(*head) = b;
else if(b->prev == NULL)
(*head) = a;
if(a->next == b){
if(aPrev != NULL) aPrev->next = b;
b->prev = aPrev;
b->next = a;
bNext->prev = a;
a->prev = b;
a->next = bNext;
}else{
b->next = aNext;
a->next = bNext;
if(a->prev != NULL)
aPrev->next = b;
if(b->prev != NULL)
bPrev->next = a;
if(a->next != NULL)
aNext->prev = b;
if(bNext != NULL)
bNext->prev = a;
if(b != NULL)
b->prev = aPrev;
if(a != NULL)
a->prev = bPrev;
}
}
Following the idea that #ggorlen gave me, I rewrote the swapNodes() function adding also some new ones and finally it works perfectly. To keep track of where the nodes were before extracting them, I created a struct containing the index returned from the findIndex() function and the node itself. I also changed the findNode() function so that it returns a variable of type node* and not node**. Sure it's not very efficient, but I'll make do.
typedef struct _extractedNode{
struct _node* node;
int index;
}extractedNode;
int findIndex(node* head, node* node){
int i=1;
node* temp = head;
while(node != temp){
temp = temp->next;
i++;
}
return i;
}
extractedNode extractNode(node** head, node* node){
extractedNode extracted;
extracted.index = 0;
if(node == NULL){
printf("extractNode(): il nodo non esiste!\n");
extracted.node = NULL;
extracted.index = -1;
}else{
node* prev = node->prev;
node* next = node->next;
if(prev == NULL){
(*head) = next;
extracted.index = 1;
}
if(extracted.index != 1)
extracted.index = findIndex(*head, node);
if(prev != NULL)
prev->next = next;
if(next != NULL)
next->prev = prev;
node->next = NULL;
node->prev = NULL;
extracted.node = node;
}
return extracted;
}
void listInsertAsIndex(node** head, int index, node* node){
if(index <= 0) return;
if(index == 1) return listInsert(head, node);
else{
node* prev = findNode(*head, index-1);
node* next = prev->next;
prev->next = node;
node->prev = prev;
if(next != NULL){
node->next = next;
next->prev = node;
}
}
}
void swapNodes(node** head, node* a, node* b){
if(a == b) return;
extractedNode aX, bX;
if(a->prev == NULL && a->next == b){
aX = extractNode(head, a);
listInsertAsIndex(head, 2, aX.node);
}else if(b->prev == NULL && b->next == a){
bX = extractNode(head, b);
listInsertAsIndex(head, 2, bX.node);
}else if(a->next == b){
aX = extractNode(head, a);
listInsertAsIndex(head, aX.index +1, aX.node);
}else if(b->next == a){
bX = extractNode(head, b);
listInsertAsIndex(head, bX.index +1, bX.node);
}else{
aX = extractNode(head, a);
bX = extractNode(head, b);
if(aX.index < bX.index){
listInsertAsIndex(head, aX.index, bX.node);
listInsertAsIndex(head, bX.index +1, aX.node);
}else{
listInsertAsIndex(head, bX.index, aX.node);
listInsertAsIndex(head, aX.index, bX.node);
}
}
}

In C why does my clearList function not work

I'm trying to clear a list. I keep getting an error that says free() called on an unallocated pointer current. I'm not sure what the problem is I have seen multiple sites use this code.
This is the whole program upon request:
I am only suppose to fill in these three functions.
#include "orderedList.h"
Node *orderedInsert(Node *p, int newval)
/* Allocates a new Node with data value newval
and inserts into the ordered list with
first node pointer p in such a way that the
data values in the modified list are in
nondecreasing order as the list is traversed.
*/
{
Node * q = NULL;
q = (Node*)malloc(sizeof(Node));
q->data = newval;
q->next = NULL;
if (q == NULL)
{
return q;
}
if (p == NULL || newval <= p->data )
{
q->next = p->next;
return q;
}
Node *tmp, *last;
tmp = (Node*)malloc(sizeof(Node));
tmp = p;
while (tmp->next != NULL && tmp->data <= newval)
{
last = tmp;
tmp = tmp->next;
}
q->next = tmp;
last->next = q;
return p;
}
void printList(FILE *outfile, Node *p)
/* Prints the data values in the list with
first node pointer p from first to last,
with a space between successive values.
Prints a newline at the end of the list.
*/
{
Node* temp = p;
while(temp != NULL)
{
printf("%d ", temp->data);
temp = temp->next;
}
printf("\n");
}
void clearList(Node **p)
/* Deletes all the nodes in the list with
first node pointer *p, resulting in *p
having value NULL. Note that we are passing
a pointer by address so we can modify that
pointer.
*/
{
Node* current = *p;
Node* temp;
while(current != NULL)
{
temp = current->next;
free(current);
current = temp;
}
*p = NULL;
}
sample code
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
typedef struct node {
int data;
struct node *next;
} Node;
Node *orderedInsert(Node *p, int newval){
Node *q;
if(NULL==(q = (Node*)malloc(sizeof(Node)))){
perror("malloc");
exit(EXIT_FAILURE);
}
q->data = newval;
q->next = NULL;
if (p == NULL || newval <= p->data ){
q->next = p;
return q;
}
Node *tmp = p, *last;
while (tmp != NULL && tmp->data < newval) {
last = tmp;
tmp = tmp->next;
}
q->next = tmp;
last->next = q;
return p;
}
void printList(FILE *outfile, Node *p){
Node* temp = p;
while(temp != NULL){
fprintf(outfile, "%d ", temp->data);
temp = temp->next;
}
fprintf(outfile, "\n");
}
void clearList(Node **p){
Node* current = *p;
while(current != NULL){
Node *temp = current->next;
free(current);
current = temp;
}
*p = NULL;
}
int main (void){
Node *head = NULL;
int i, v;
printf("The generated number\n");
for(i=0; i<10; ++i){
v = rand()%10;
printf("%d ", v);
head = orderedInsert(head, v);
}
printf("\n");
printf("The orderd number\n");
printList(stdout, head);
clearList(&head);
return 0;
}
The code is fundamentally ok, supposing that you don't need to free anything other than the Node objects themselves. The problem is likely with your list. In particular, if it contains a loop then you will see the behavior you describe, because your function will eventually come back to a Node it has already freed.
please read my added comments regarding the OPs code
#include "orderedList.h"
Node *orderedInsert(Node *p, int newval)
/* Allocates a new Node with data value newval
and inserts into the ordered list with
first node pointer p in such a way that the
data values in the modified list are in
nondecreasing order as the list is traversed.
*/
{
Node * q = NULL;
q = (Node*)malloc(sizeof(Node));
q->data = newval; // if q is NULL, then setting an offset from address 0
// which is a real good way to cause a seg fault event
q->next = NULL; // if q is NULL, then setting an offset from address 0
// which is a real good way to cause a seg fault event
if (q == NULL)
{
return q; // odd, returning a null,
// I would expect to return p
}
if (p == NULL || newval <= p->data )
{
q->next = p->next; // odd, if p was null (I.E. adding first entry into list)
// then p->next is some offset from address 0
// a real good way to cause a seg fault event
// if not first entry in list and new data < first entry in list data
// then set q->next to be inserted before the current/existing list
// however,
// (assuming p is the head of the list and not a ptr to the first entry)
// then p->next needs to be set to q
return q;
}
Node *tmp, *last;
tmp = (Node*)malloc(sizeof(Node)); // failed to check if malloc was successful
tmp = p; // overlays the pointer to the 'just' malloc'd memory
// and a good way to cause a seg fault event if malloc failed
-- I stopped checking the code here --
while (tmp->next != NULL && tmp->data <= newval)
{
last = tmp;
tmp = tmp->next;
}
q->next = tmp;
last->next = q;
return p;
}
void printList(FILE *outfile, Node *p)
/* Prints the data values in the list with
first node pointer p from first to last,
with a space between successive values.
Prints a newline at the end of the list.
*/
{
Node* temp = p;
while(temp != NULL)
{
printf("%d ", temp->data);
temp = temp->next;
}
printf("\n");
}
void clearList(Node **p)
/* Deletes all the nodes in the list with
first node pointer *p, resulting in *p
having value NULL. Note that we are passing
a pointer by address so we can modify that
pointer.
*/
{
Node* current = *p;
Node* temp;
while(current != NULL)
{
temp = current->next;
free(current);
current = temp;
}
*p = NULL;
}

Sorting a linked list in C

I'm trying to sort a linked list by finding the largest value, deleting it from its position, and then inserting it at the top of the list.
The difficulty I'm running into is the actual deleting and inserting at the top. The issue seems to be in the if condition in the while loop contained within the sortList function, but I'm not sure how to fix it.
Any help would be appreciated.
#include <stdio.h>
#include <stdlib.h>
typedef struct node{
int num;
struct node *next;
} Node, *NodePtr;
void printList(NodePtr np);
NodePtr makeList(void);
NodePtr makeNode(int n);
NodePtr sortList(NodePtr list);
int main(void) {
NodePtr list;
printf("Enter numbers for the list (0 to end)\n");
list = makeList();
printList(list);
list = sortList(list);
printList(list);
return 0;
}
NodePtr makeList(void) {
NodePtr makeNode(int), np, top, last;
int n;
top = NULL;
if(scanf("%d", &n) != 1)n = 0;
while(n != 0) {
np = makeNode(n);
if(top == NULL)top = np;
else last->next = np;
last = np;
if(scanf("%d", &n)!=1)n=0;
}
return top;
}
void printList(NodePtr np) {
while(np != NULL) {
printf("%d\n", np->num);
np = np->next;
}
}
NodePtr makeNode(int n) {
NodePtr np = (NodePtr)malloc(sizeof(Node));
np->num = n;
np->next = NULL;
return np;
}
NodePtr sortList(NodePtr list) {
NodePtr top = list;
NodePtr curr = NULL;
NodePtr largest;
NodePtr prev;
prev = NULL;
curr = top;
largest = top;
while(curr != NULL) {
prev = curr;
if(curr->num > largest->num) {
largest = curr;
prev->next = curr->next;
largest->next = top;
}
curr = curr->next;
}
if(prev == NULL) {
largest->next = top;
return largest;
}
return largest;
}
There is issues in the sortList function.
This function only put some large nodes in the beginning of the list. It is not soting all the list. you can you a sort algorithm to sort the file : quicksort/ bubblesort/...
i put a code doing a sort in the end of this answer.
here is a code doing the sort of the list :
//it is replacing largest node with first one then doing the same operation with sublist (list-first element)
NodePtr sortList(NodePtr list)
{
//
if(list == null || list->next == null)
return list; // the list is sorted.
//replace largest node with the first :
//1- find largest node :
NodePtr curr, largest,largestPrev;
curr = list;
largest = list;
prev = list;
largestPrev = list;
while(curr != NULL) {
if(curr->num > largest->num) {
largestPrev = prev;
largest = curr;
}
prev = curr;
curr = curr->next;
}
//largest node is in largest.
//2- switching firt node and largest node :
NodePtr tmp;
if(largest != list)
{
largestPrev->next = list;
tmp = list->next;
list->next = largest->next;
largest->next = tmp;
}
// now largest is the first node of the list.
// calling the function again with the sub list :
// list minus its first node :
largest->next = sortList(largest->next);
return largest;
}
Here is my attempt to sort a singly linked list using QuickSort algorithm. If you know n then run time will be O(n log n). Check if this helps.
#include "malloc.h"
typedef struct node {
struct node *next;
int val;
} node;
bool insert_node(struct node **head, int val)
{
struct node *elem;
elem = (struct node *)malloc(sizeof(struct node));
if (!elem)
return false;
elem->val = val;
elem->next = *head;
*head = elem;
return true;
}
int get_lval(struct node *head, int l)
{
while(head && l) {
head = head->next;
l--;
}
if (head != NULL)
return head->val;
else
return -1;
}
void swap(struct node *head, int i, int j)
{
struct node *tmp = head;
int tmpival;
int tmpjval;
int ti = i;
while(tmp && i) {
i--;
tmp = tmp->next;
}
tmpival = tmp->val;
tmp = head;
while(tmp && j) {
j--;
tmp = tmp->next;
}
tmpjval = tmp->val;
tmp->val = tmpival;
tmp = head;
i = ti;
while(tmp && i) {
i--;
tmp = tmp->next;
}
tmp->val = tmpjval;
}
struct node *Quick_Sort_List(struct node *head, int l, int r)
{
int i, j;
int jval;
int pivot;
i = l + 1;
if (l + 1 < r) {
pivot = get_lval(head, l);
printf("Pivot = %d\n", pivot);
for (j = l + 1; j <= r; j++) {
jval = get_lval(head, j);
if (jval < pivot && jval != -1) {
swap(head, i, j);
i++;
}
}
swap(head, i - 1, l);
Quick_Sort_List(head, l, i);
Quick_Sort_List(head, i, r);
}
return head;
}
struct node *Sort_linkedlist(struct node *head)
{
struct node *tmp = head;
// Using Quick sort.
int n = 0;
while (tmp) {
n++;
tmp = tmp->next;
}
printf("n = %d\n", n);
head = Quick_Sort_List(head, 0, n);
return head;
}
void print_list(struct node *head)
{
while(head) {
printf("%d->", head->val);
head = head->next;
}
printf("\n");
}
int _tmain(int argc, _TCHAR* argv[])
{
struct node *head = NULL;
struct node *shead = NULL;
insert_node(&head, 10);
insert_node(&head, 12);
insert_node(&head, 9);
insert_node(&head, 11);
insert_node(&head, 7);
insert_node(&head, 1);
insert_node(&head, 3);
insert_node(&head, 8);
insert_node(&head, 5);
insert_node(&head, 2);
insert_node(&head, 4);
insert_node(&head, 6);
print_list(head);
shead = Sort_linkedlist(head);
print_list(shead);
return 0;
}
By writing to largest->next you overwrote curr->next. So you end up restarting from the top all the time.
Make sure that:
the list remains consistent
your list iterator remains consistent
But overall, your code seems to be heavily broken, I believe there might be a couple other errors in your sorting logic.
The following are some of the problems which exist in your sorting logic:
You are setting the prev pointer to curr in the beginning of the loop itself which is incorrect. By doing this, you are making the current pointer and the previous node pointer as same which makes it impossible to delete the node.
You should assign the largest pointer also to top whereby it facilitates the possibility of setting the largest->next to real top node.
The code can modified like below (Just a pointer, you need to check for other issues yourself):
while(curr != NULL)
{
if(curr->num > largest->num)
{
largest = curr;
prev->next = curr->next;
largest->next = top;
top = largest;
}
prev = curr;
curr = curr->next;
}
// Program to sort a single linked list in ascending order
// (without exchanging data in the nodes)
/**************************************************************************
There are two methods of sorting presented here(At a time,we can use any of
these two functions to sort our single linked list.) -
1. Function 'void Sort()' - This function uses selection sort method(I
think).
In this function,a node whose data is the smallest in the list is made
as 'head' node(i.e. starting node of the list) by scanning the whole list
once.Then from the remaining list,again a node with the smallest data is
found out whose address is kept in the 'next' field of previous node(head
node).This process continues to sort the whole list.
2. Function 'void Sort_method2()' - This function uses insertion sort
method(I think).
In this function,starting from second node in the list, all previous node
data(starting from 'head' node) are compared with current reference node
(which is initially second node in the list).If 'data' field of current
reference node is smaller than that of any of its previous nodes,then
suitable changes in the 'next' field of corresponding nodes are made.If
data in the current reference node is smaller than that in the 'head' node,
then the current reference node is made as 'head' node.
*********************************************************************/
#include<stdio.h>
#include<conio.h>
#include<alloc.h>
#include<stdlib.h>
struct node
{
int data;
struct node *next;
};
struct node *head,*head1;
void Create_node(int data);
void display();
void Sort();
void Sort_method2();
void main()
{
int choice,d;
clrscr();
while(1)
{
printf("\n 1.Create new node");
printf("\n 2.Sort in ascending order");
printf("\n 3.Exit");
printf("\nEnter your choice : ");
scanf("%d",&choice);
switch(choice)
{
case 1: printf("\nEnter data :");
scanf("%d",&d);
Create_node(d);
break;
case 2: Sort(); // At a time,we can use any of these two
//Sort_method2(); // functions to sort our single linked list.
break;
case 3: exit(0);
default:exit(0);
}
} // end of while(1)
} // end of main()
//--------------------------------------------
void Create_node(int d)
{
struct node *newnode,*temp;
newnode = (struct node *)malloc(sizeof(struct node));
newnode -> data = d;
newnode -> next = NULL;
if(head == NULL)
head = newnode;
else
{
temp = head;
while(temp -> next != NULL)
temp = temp -> next;
temp -> next = newnode;
} // end of 'else'
} // end of 'Create_node(int d)'
//---------------------------------------------
void display() // Print linked list contents
{
struct node *temp;
printf("\nList contents are :\n");
temp = head;
while(temp != NULL)
{
printf(" Data = %d Address = %u\n",temp->data,temp);
temp = temp->next;
}
printf("\n");
}
//--------------------------------------------
void Sort()
{
struct node *t,*t1,*t2,*t3;
t1 = head;
head1 = head;
if(head == NULL)
printf("\nThe linked list is empty!");
else
{
while( (t2 = t1 -> next) != NULL)
{
while(t2 != NULL)
{
t3 = t2 -> next;
if( t1 -> data > t2 -> data)
{
t2 -> next = t1;
for(t = t1; t -> next != t2;t = t -> next);
t -> next = t3;
t1 = t2; // t1 = Node with smaller data
t2 = t3; // t2 = Node to be compared with t1
} // end of 'if'
else
{
// t1 = t1; // That is,no change in t1.
t2 = t3;
}
} // end of ' while(t2 != NULL)'
if(head == head1) // We want this action only for first pass of
{ // outer while() loop.Only initially, head = head1.
head = t1;
head1 = t1 -> next;
} // end of 'if(head == head1)'
else
{
for(t = head;t -> next != head1; t = t -> next);
t -> next = t1;
head1 = t1 -> next;
} // end of 'else'
t1 = t1 -> next;
} // end of 'while( (t2 = t1 -> next) != NULL)'
display(); // Display the list.
} // end of 'else' of 'if(head == NULL)'
} // end of 'Sort()'
//--------------------------------------------
void Sort_method2()
{
struct node *t,*t1,*t2,*tt;
if(head == NULL)
printf("\nThe linked list is empty!");
else
{
t1 = head -> next;
while(t1 != NULL) // This is i-loop(outer loop).
{
t2 = t1 -> next;
for(t = head; t != t1; t = t -> next) // This is j-loop(inner loop).
{
if(t1->data < t->data)
{
t1 -> next = t;
for(tt=head; tt->next != t1; tt=tt->next); //end of for loop in 'if'
tt -> next = t2;
if(t == head)
head = t1; // There is only one statement in this 'if'.
else // i.e.,'if(t != head)'
{
for(tt=head; tt->next != t; tt=tt->next);
tt -> next = t1;
}
break;
} // end of 'if'
} // end of outer 'for' loop
t1 = t2;
} // end of 'while'
display(); // Display the list.
} // end of 'else' of 'if(head == NULL)'
} // end of 'Sort_method2()'

Resources