Double linked lists: swapping function doesn't always work - c

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

Related

error signal(SIGABRT) raised in C program

Couldn't understand why my program is producing an error signal.
#include<stdio.h>
#include<stdlib.h>
struct Node{
int data;
struct Node *next;
};
int MAX_SIZE = 1;
char stack[1];
int top = -1;
int isempty() {
if(top == -1)return 1;
else return 0;
}
int isfull() {
if(top == 0)return 1;
else return 0;
}
int pop() {
int data;
if(!isempty()) {
data = stack[top];
top = top - 1;
return data;
} else {
printf("Could not retrieve data, Stack is empty.\n");
}
}
void push(int data) {
if(!isfull()) {
top = top + 1;
stack[top] = data;
} else {
printf("Could not insert data, Stack is full.\n");
}
}
struct Node* newNode(int d){
struct Node *temp = (struct Node*)malloc(sizeof(struct Node));
temp->data = d;
temp->next = NULL;
return temp;
}
struct Node* reverse(struct Node* head){
//reverses the linked list and returns the pointer pointing to the first node of the reversed linked list.
struct Node *prev = NULL, *curr = head;
while (curr) {
struct Node* temp = curr->next;
curr->next = prev;
prev = curr;
curr = temp;
free(temp);
}
head = prev;
return head;
}
struct Node* addition(struct Node* first, struct Node* second){
struct Node *rev1, *rev2;
struct Node *res = NULL, *revres = NULL;
struct Node *temp, *prev = NULL;
int carry = 0, sum;
rev1 = reverse(first);
rev2 = reverse(second);
while (rev1 != NULL || rev2 != NULL) {
sum = carry + (rev1 ? rev1->data : 0) + (rev2 ? rev2->data : 0);
carry = (sum >= 1000) ? 1 : 0;
sum = sum % 1000;
temp = newNode(sum);
if (res == NULL)
res = temp;
else
prev->next = temp;
prev = temp;
if (rev1)
rev1 = rev1->next;
if (rev2)
rev2 = rev2->next;
}
if (carry > 0){
struct Node *new = newNode(carry);
temp->next = new;
free(new);
}
revres = reverse(res);
while (revres->data == 0 && revres->next) {
struct Node* temp = revres;
revres = revres->next;
free(temp);
}
return revres;
}
int length_reversal(struct Node** head_ref){
// reverses the given linkedlist in-place and also returns the number of nodes in the list.
struct Node* prev = NULL;
struct Node* current = *head_ref;
struct Node* next;
int len = 0;
while (current != NULL) {
len++;
next = current->next;
current->next = prev;
prev = current;
current = next;
}
*head_ref = prev;
return len;
}
void addData(struct Node** head_ref, int new_data){
struct Node* new_node = newNode(new_data);
new_node->next = (*head_ref);
(*head_ref) = new_node;
free(new_node);
}
struct Node* make_empty_list(int size){
struct Node* head = NULL;
while (size--)
addData(&head, 0);
return head;
}
struct Node* multiplication(struct Node* first, struct Node* second){
int m = length_reversal(&first), n = length_reversal(&second);
struct Node* result = make_empty_list(m + n + 1);
struct Node *second_ptr = second, *result_ptr1 = result, *result_ptr2, *first_ptr;
while (second_ptr) {
int carry = 0;
result_ptr2 = result_ptr1;
first_ptr = first;
while (first_ptr) {
int mul = first_ptr->data * second_ptr->data + carry;
result_ptr2->data += mul % 1000;
carry = (mul / 1000) + (result_ptr2->data / 1000);
result_ptr2->data = result_ptr2->data % 1000;
first_ptr = first_ptr->next;
result_ptr2 = result_ptr2->next;
}
if (carry > 0) {
result_ptr2->data += carry;
}
result_ptr1 = result_ptr1->next;
second_ptr = second_ptr->next;
}
length_reversal(&result);
length_reversal(&first);
length_reversal(&second);
while (result->data == 0 && result->next) {
struct Node* temp = result;
result = result->next;
free(temp);
}
return result;
}
struct Node* input(FILE* fp){
char ch;
int i = 0;
struct Node *result = NULL, *first= NULL;
struct Node *it1 = NULL, *it2 = NULL, *it3 = NULL;
char str[3];
while(EOF != (ch=fgetc(fp)) && ch != '\n'){
if(ch == '=')return it1;
else if(ch == '0'||ch == '1'||ch == '2'||ch == '3'||ch == '4'||ch == '5'||
ch == '6'||ch == '7'||ch == '8'||ch == '9'){
if(i==3){printf("invalid input\n"); return NULL;}
str[i] = ch;
i++;
}
else if(ch == '+'){
push(ch);
}
else if(ch == '*'){
push(ch);
}
else if(ch == '$'){
it3 = newNode(atoi(str));
i = 0;
if(!first){
if(!it1)it1 = it3;
else it2 = it3;
}
else{
first->next = it3;
first = NULL;
}
if(!isempty()){
char c = pop();
if(c == '+'){result = addition(it1, it2); it1 = result; it2 = NULL;}
if(c == '*'){result = multiplication(it1, it2); it1 = result; it2 = NULL;}
}
}
else if(ch == ','){
if(first != NULL){
it3 = newNode(atoi(str));
first->next = it3;
first = first->next;
i=0;
}
else{
if(!it1){
first = newNode(atoi(str));
it1 = first;
i=0;
}
else{
first = newNode(atoi(str));
it2 = first;
i=0;
}
}
}
else if(ch == ' ') continue;
else {
printf("Invalid input");
return NULL;
}
}
return it1;
}
void output(FILE *fout, struct Node* list) {
struct Node *temp;
for (temp = list; temp->next != NULL; temp = temp->next)
fprintf (fout, "%03d,", temp->data);
fprintf(fout, "%03d$", temp->data);
fprintf (fout, "\n");
}
int main(){
FILE *fp;
fp = fopen("input_txt.txt", "r");
char c;
while(EOF != (c=getc(fp)) && c != '='){
ungetc(c, fp);
struct Node* res = input(fp);
if(res){
output(stdout, res);
}
}
return 0;
}
I have tried using a debugger to understand the problem, but no luck there.
The problem was described as
"""You will represent an arbitrarily large unsigned integer I by a singly linked list of its DIGITs d1 ,
d2 , ... , dm , where d1 is the least significant DIGIT of I and dm is the most significant DIGIT of I.
Assume that the DIGITs are from a number system with base 1,00010. Implement each DIGIT as a C
unsigned int with DIGIT values in [0, 999].
a) Write C functions to perform the arithmetic operations addition and multiplication of large
unsigned integers.
b) Write a C function to input a large unsigned integer from stdin as comma separated DIGITs
in decimal, ordered on decreasing significance and terminated by a $
c) Write a C function to output a large unsigned integer to stdout in the format used for input,
showing each DIGIT as 3 decimal digits.
d) Write a C main() which will repeatedly accept (from stdin) and evaluate, large integer infix
expressions on large unsigned integer constants using the operators “+” (addition) and “*”
(multiplication). An expression is terminated by “=”. On encountering an “=”, the value of
the expression is to be printed to stdout. Evaluate expressions from left to right. The main() loop
should terminate when it receives an empty expression (terminated by =)."""
This was my assignment question for which the deadline was over a week ago and I couldn't figure out the problem with my code.
For example, the 2 line input
111,041,411,111,011$ + 222,222$ * 003$ =
results in the output
333,124,233,999,699$

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;

Printing a doubly linked list in reverse only printing first element

Writing a function to print a doubly linked list in reverse. The function stops after only printing 7 and does not print the rest of the items in the list. My programs and functions are below.
Edited to include code that didn't paste. Having issues copying and pasting with Putty my apologies.
#include <stdio.h>
#include <stdlib.h>
struct node
{
int data;
struct node *next;
struct node *prev;
};
typedef struct node node;
void printRev(node* head);
node* removeNode(node* head, int d);
node* insertFront(node* head, int d);
node* insertBack(node* head, int d);
void print(node* head);
int max(node* head);
int min(node* head);
int locInList(node* head, int x);
int main()
{
node* head = NULL;
head = insertFront(head, 5);
head = insertFront(head, 4);
head = insertBack(head, 6);
head = insertBack(head, 7);
print(head);
printRev(head);
printf("Max: %d\n", max(head));
printf("Min: %d\n", min(head));
printf("locInList 5: %d\n", locInList(head, 5));
printf("locInList 9: %d\n", locInList(head, 9));
head = removeNode(head, 6);
print(head);
head = removeNode(head, 4);
print(head);
head = removeNode(head, 7);
print(head);
return 0;
}
void printRev(node* head) {
node *cur = head;
node *tmp = NULL;
if (cur == NULL) {
return;
}
else {
while(cur->next != NULL) {
cur = cur->next;
}
while(cur != NULL) {
printf("%d ", cur->data);
cur = cur->prev;
}
}
printf("\n");
}
node* removeNode(node* head, int d)
{
node *tmp = head->next;
head->data = head->next->data;
head->next = tmp->next;
free(tmp);
return head;
}
node* insertFront(node* head, int d)
{
node *tmp = NULL;
tmp = malloc(sizeof(node));
tmp->data = d;
tmp->next = head;
head = tmp;
return head;
}
node* insertBack(node* head, int d)
{
node *tmp = malloc(sizeof(node));
tmp->data = d;
tmp->next = NULL;
if(head == NULL){
return head;
}
}
else{
node *end = head;
while(end->next != NULL){
end = end->next;
}
end->next = tmp;
}
return head;
}
void print(node* head)
{
node *tmp = head;
while(tmp != NULL){
printf("%d ", tmp->data);
tmp = tmp->next;
}
printf("\n");
}
int max (node* head)
{
int max = head->data;
node *tmp = NULL;
tmp = head;
while(tmp->next != NULL){
if(tmp->data >= max){
max = tmp->data;
}
tmp = tmp->next;
}
}
return min;
}
int locInList(node* head, int x)
{
int i = 0;
node *tmp = NULL;
tmp = head;
while(tmp != NULL){
if(tmp->data == x){
return i;
}else{
i++;
tmp = tmp->next;
} }
return -1;
}
Expected results are - 7 6 5 4
Received results are - 7
Neither insertFront nor insertBack set prev, which is the root cause of your problem. (Your reverse iteration loop critically depends on the prev pointers having been set correctly.)
As it's a doubly linked list, you should point your head's back pointer to temp(new inserted one) in the function insertFront. So it should be ;
node* insertFront(node* head, int
d)
{
node *tmp = NULL;
tmp = malloc(sizeof(node));
tmp->data = d;
tmp->prev=NULL:
if(head==NULL)
return tmp;
head->prev=tmp;
tmp->next = head;
return tmp;
}
Similarly in insertBack function take care of making prev pointer point to previous node in the list.

C: Recursive sorting of linked list

I'm trying to implement a recursive sorting algorithm for linked list structure. C language.
My algorithm is this:
1) find max value in list
2) remove it from the list and insert it at Head node
3) start algorithm again from next node
4) run until you reach end of list
I have something, but it doesn't 'remember' my list. I realize I'm making a mistake somewhere (probably recursive calls), but I can't understand how to fix it.
typedef struct Node{
int data;
struct Node* next;
} Node;
void insert(Node** head, int val)
{
//insert at top
Node* to_insert = (Node*)malloc(sizeof(Node));
to_insert->data = val;
to_insert->next = (*head);
(*head) = to_insert;
}
Node* sort_ll(Node* head)
{
//base case, iterated trough entire list
if(head == NULL)
return NULL;
int max = 0;
Node* tmp = head;
Node* to_move = tmp;
//find maximum value
while(tmp != NULL) {
if(tmp->data > max) {
max = tmp->data;
to_move = tmp;
}
tmp = tmp->next;
}
//if its currently top, leave it there
if(to_move == head) {
return sort_ll(head->next);
}
//find node with max value
tmp = head;
while(tmp->next != to_move) {
tmp = tmp->next;
}
//cut it out from the list
tmp->next = tmp->next->next;
free(to_move);
//insert value at the head of the list
insert(&head, max);
return sort_ll(head->next);
}
int main()
{
Node* list = NULL;
insert(&list, 3);
insert(&list, 6);
insert(&list, 7);
insert(&list, 2);
insert(&list, 1);
insert(&list, 5);
insert(&list, 4);
list = sort_ll(list);
Node* tmp = list;
while(tmp != NULL) {
printf("%d\n", tmp->data);
tmp = tmp->next;
}
return 0;
}
fix like this
Node *sort_ll(Node* head){
if(head == NULL || head->next == NULL)
return head;//There is no need for processing
int max = head->data;
Node *prev = head;
Node *to_move = NULL;
Node *tmp = head->next;
//find maximum value in rest(head->next)
while(tmp != NULL) {
if(tmp->data > max) {
max = tmp->data;
to_move = prev;//save previous node for remove link
}
prev = tmp;
tmp = tmp->next;
}
if(to_move == NULL) {//not find in rest
head->next = sort_ll(head->next);
return head;
}
prev = to_move;
to_move = prev->next;//max node
prev->next = prev->next->next;//max node remove from link
to_move->next = sort_ll(head);
return to_move;
}

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