Trying to sort a linked list - c

There are many implementations available on the net, but I wanted to do it on my own.
Can anyone tell what mistakes I am making?
When I created the linked list, I gave input as 3,12,5,2. So after sorting it should have been 2,3,5,12, but it gave me output as 3,5,2,12.
#include <stdio.h>
#include <stdlib.h>
struct node
{
int data;
struct node *next;
};
struct node *start=NULL;
void sort()
{
struct node *preptr, *ptr, *temp;
temp = (struct node *)malloc(sizeof(struct node));
ptr=start;
while(ptr->next != NULL)
{
preptr=ptr;
ptr=ptr->next;
if (preptr->data > ptr->data )
{
temp->data=ptr->data;
ptr->data=preptr->data;
preptr->data=temp->data;
ptr=start;
}
}
}

You appear to have attempted to implement Bubble Sort, but that requires multiple passes through the data in the general, and you perform only one. On that one pass, with input 3, 12, 5, 2, your code
compares 3 with 12, and makes no change;
compares 12 with 5, and swaps them;
compares 12 with 2, and swaps them.
Then it stops, leaving 3, 5, 2, 12 as the final result.
A Bubble Sort on an n-element list must make n - 1 passes through the list in the general case, and your particular input happens to require that maximum number of passes. One way to fix it would be to just run your existing code for one sorting pass inside a for loop that runs n - 1 times, but of course you then need to compute n first. A better way (without changing to an altogether better algorithm) would be to run an indeterminate number of passes, via an outer loop, keeping track of whether any swaps are performed during the pass. You're then done when you complete a pass without making any swaps.
Additional notes:
You don't need a struct node just to swap the int data of two nodes.
If want a struct node for a local temporary, you don't need to allocate it dynamically. Just declare it:
struct node temp_node;
If you want a struct node * for a local temporary, you (probably) do not need to allocate any memory for it to point to.
If you want a struct node for a local temporary and a pointer to it, you still don't need to allocate anything dynamically. Just declare the struct and take its address:
struct node temp_node;
struct node *temp = &temp_node;
The main reasons to allocate dynamically are that you don't know in advance how much memory you will need, or that the allocated object needs to outlive the execution of the function in which it is created.
Sorting a linked list is usually accomplished by rearranging the nodes by changing their links, not by swapping the node payloads, as your function does. It's not necessarily wrong to swap the payloads, but that does not take any advantage of the linked list structure.

As you wrote in comments that you actually need to move the nodes, not the values, you will need to reassign the next pointers.
For the same reason, it must be possible for start to reference a different node. Therefore I would suggest that sort takes start as an argument and returns the new value it.
For implementing bubble sort, you need an extra outer loop, which restarts the iteration over the list. This should be repeated at most n times, where n is the number of nodes in your list. You could also just check whether a swap was necessary and in that case decide to do another scan through your list... until no more swaps occur.
I have here implemented that second idea:
#include <stdio.h>
#include <stdlib.h>
struct node {
int data;
struct node *next;
};
// A function to create a new node.
// This allows for easy initialisation of a linked list
struct node *newNode(int data, struct node *next) {
struct node *temp = (struct node *)malloc(sizeof(struct node));
temp->data = data;
temp->next = next;
return temp;
}
// Useful to see what is in the list...
void printList(struct node *cur) {
while (cur != NULL) {
printf("%i ", cur->data);
cur = cur->next;
}
printf("\n");
}
// Let the sort function
struct node * sort(struct node *start) {
struct node *prev, *cur, *next;
// flag indicating we are not sure yet that
// the list is sorted
int mutation = 1;
// extra dummy node that precedes the start node
struct node sentinel;
sentinel.next = start;
while (mutation) {
mutation = 0;
prev = &sentinel;
cur = sentinel.next;
next = start->next;
while (next != NULL) {
if (cur->data > next->data ) {
// swap cur and next
prev->next = next;
cur->next = next->next;
next->next = cur;
// flag that we need more iterations
mutation = 1;
// prepare for next iteration
prev = next;
} else {
prev = cur;
cur = next;
}
next = cur->next;
}
}
return sentinel.next;
}
// demo:
int main(void) {
// Create list that was given as example
struct node *start = newNode(3, newNode(12, newNode(5, newNode(2, NULL))));
printf("Input:\n");
printList(start);
start = sort(start);
printf("Sorted:\n");
printList(start);
return 0;
}

Related

Weird values in free() function C

I want to delete the first node of a linked list (You can see below the image)
Τhe structures are as follows:
typedef struct PageEntry { //Node
unsigned int page_number;
char mode;
int count, R;
struct PageEntry *next;
}PE;
typedef struct Element {
int val;
PE* pe;
}Element;
typedef struct PageTable {
int p_faults, reads, writes, disk_writes, maxFrames, usedFrames;
char* algorithm;
Element* el;
}PT;
My code for trying delete the first node is here.
PE *cur = pt->el[pos].pe;
PE *prev =NULL, *temp = cur;
if(cur->count == min){ //head node
if(cur->mode == 'W'){
pt->disk_writes++;
}
if (cur->next == NULL) {
memset(cur, 0, sizeof(PE));
free(pt->el[pos].pe);
cur = NULL;
}
else {
cur = temp->next;
free(temp);
}
I am working with Visual Studio and when i do free i get back some weird values as you can see at the sceenshot. I cant unsterstand what's happening
Your diagram does not describe a list, but an array of lists. And that's fine in itself. But - why are you mixing up the code for an actual list with the code of working with the page table as a whole? It's not clear where exactly you decide you need to delete a list node (i.e. a page entry). You're also implicitly assuming the list is not empty. You're memsetting needlessly. Finally, and most importantly - when you free(temp) - you don't set pt->el[pos].pe to point to cur->next. So, it continues to point to the element you've just freed.

Merge Sort On Linked List in C

Merge sort is often preferred for sorting a linked list. The slow random-access performance of a linked list makes some other algorithms (such as quicksort) perform poorly, and others (such as heapsort) completely impossible.
I have been struggling to do Merge Sort on a linked list. It keeps throwing back an error. I'm providing the code I've tried to execute. Please do help me out.
It keeps giving runtime error.
#include <stdio.h>
#include <stdlib.h>
struct node {
int data;
struct node *next;
};
struct node *SortedMerge(struct node *a, struct node *b);
void FrontBackSplit(struct node *source, struct node *frontref, struct node *backref);
struct node *Create(struct node *head, int num) {
struct node *newnode, *temp;
newnode = (struct node *)malloc(sizeof(struct node));
newnode->data = num;
newnode->next = NULL;
if (head == NULL) {
head = newnode;
temp = newnode;
} else {
temp->next = newnode;
temp = temp->next;
}
temp->next = NULL;
return head;
}
struct node *display(struct node *head) {
struct node *temp;
temp = head;
while (temp != NULL) {
printf("%d->", temp->data);
temp = temp->next;
}
printf("NULL");
return head;
}
struct node *MergeSort(struct node *head) {
struct node *headref, *a, *b;
headref = head;
if ((head == NULL) || (head->next) == NULL) {
return;
}
FrontBackSplit(headref, a, b);
MergeSort(a);
MergeSort(b);
head = SortedMerge(a, b);
return head;
}
void FrontBackSplit(struct node *source, struct node *frontref, struct node *backref) {
struct node *fast, *slow;
slow = source;
fast = source->next;
while (fast != NULL) {
fast = fast->next;
if (fast != NULL) {
slow = slow->next;
fast = fast->next;
}
}
frontref = source;
backref = slow->next;
slow->next = NULL;
}
struct node *SortedMerge(struct node *a, struct node *b) {
struct node *result;
result = NULL;
if (a == NULL) {
return (b);
}
else if (b == NULL) {
return (a);
}
if (a->data <= b->data) {
result = a;
result->next = SortedMerge(a->next, b);
} else {
result = b;
result->next = SortedMerge(a, b->next);
}
return result;
}
int main() {
struct node *head = NULL;
int i, n, num;
scanf("%d", &n);
for (i = 0; i < n; i++) {
scanf("%d", &num);
head = Create(head, num);
}
head = MergeSort(head);
display(head);
}
There are a couple of problems with the code, and which one triggers the error you are seeing I cannot say, but I will point out a few of them below. Take Create():
struct node *Create(struct node *head, int num)
{
struct node *newnode, *temp;
newnode=(struct node *)malloc(sizeof(struct node));
newnode->data=num;
newnode->next=NULL;
if(head==NULL) {
head=newnode;
temp=newnode;
} else {
temp->next=newnode;
temp=temp->next;
}
temp->next=NULL;
return head;
}
I cannot work out exactly what it is supposed to do, to be honest. Maybe add a new node to a list, represented by a head link? It doesn't do that. You create a new node
newnode=(struct node *)malloc(sizeof(struct node));
which I would suggest you write as
newnode = malloc(sizeof *newnode);
You don't need to cast void *, so you don't need to cast the result of malloc(), and using sizeof *newnode rather than sizeof(struct node) is safer. But the code works correctly in the form you have, so there is not a problem there. However, what happens with that node depends on head. If head is NULL, you point it at the new node, and through temp you (re)assign the new node's next to NULL. So now you will return an updated head that consists of the new node as a single element list. That matches my guess at what the function should do.
However, if head is not NULL, you put the new node in temp->next, which is a problem, since temp isn't initialised. You write to temp in the if(head==NULL) branch, but you dereference it in the else branch, where it can point anywhere. I am surprised if you don't get a segmentation fault from time to time here. It isn't necessary to assign the new node to temp->next, though, because immediately afterwards you change temp to point to temp->next, which is where you just put newnode, so temp = newnode would do the trick, without the segfault. But not all is well if we do that. We now would have the new node in temp (with the next pointer, again, reassigned to NULL) and then we return head. We didn't connect head with newnode anywhere, if we took the else branch. So calling Create() with a non-NULL head creates a new node, throws it away (and leaking memory), and that is all that does.
So while my guess is that Create() should add a new to a list, represented by head, or something to that effect, what it actually does is create a single-element list if the first argument is NULL, and leak sizeof(struct node) memory while doing nothing if head != NULL.
That being said, the code might work by pure luck of course. When I tried it with clang with zero optimisation, I somehow managed to build a list correctly. This is luck, though. It won't work in general. I suspect that what happens is that the repeated calls to Create() in the loop in main() happens to leave the last node you created (and wrote to temp) at the same stack location as the uninitialised temp in the next call. So by pure luck, putting the new node in temp's next appends the new node to the last node you created. It was really interesting working that one out :) But don't rely on this, of course. It is a combination of several lucky circumstances. Add optimisation flags, and the compiler will change the stack layout, and the code will break. Call other functions between successive calls to Create() and the stack will change, and then you don't have the last link on the stack any longer. And the code will break. It is a very unstable situation if this works at all.
If you just want to add a new node to a list, make a prepend function. Something like
struct node *prepend(int val, struct node *list)
{
struct node *n = malloc(sizeof *n);
if (n) {
n->data = val;
n->next = list;
}
return n;
}
(I haven't tested it, so there might by syntax errors, but it will be something like that...you need to figure out what to do if malloc() fails, but you could just abort() if you don't want to deal with it).
There is nothing wrong with display(), except that I don't understand why it is in lower-case when the other functions are in camel-case. You don't need temp, you can use head in the while-loop, but that is a style choice. The function works as intended.
With MergeSort(), however, we have another problem. I am surprised that your compiler didn't scream warnings at you here. It should really give you an error, with the right flags, but at the very least an error. When you test if the list is empty or a singleton, you return, but not with a node. The function should return a struct node *, so just using return will not give you anything useful.
if((head==NULL) || (head->next)==NULL){
return;
}
If the base case of the recursion returns garbage, obviously the whole recursion tumbles. Otherwise, assuming that the FrontBackSplit() and SortedMerge() work, the function looks okay. You don't need the extra headref variable, it is just a synonym for head, but there is nothing wrong with having it. The compiler will get rid of it for you. There isn't any need to assign the merged lists to head and then return head either. You can just return SortedMerge(a,b). But again, your compiler will handle that for you, once you turn on optimisation. Except for the base case, I believe the function should work.
In FrontBackSplit(), I get the impression that you want to get the frontref and backref values back to the caller. Otherwise, the function doesn't do anything. But when you are modifying the function parameters, you are not changing the variables in the caller's scope. You need to pass the two pointers by reference, which means that you need to use pointers to pointers. Change it to something like this:
void FrontBackSplit(struct node *source,
struct node **frontref,
struct node **backref)
{
struct node *fast, *slow;
slow=source;
fast=source->next;
while(fast!=NULL) {
fast=fast->next;
if(fast!=NULL) {
slow=slow->next;
fast=fast->next;
}
}
*frontref=source;
*backref=slow->next;
slow->next=NULL;
}
When you call the function, use the addresses of the parameters for the second and third argument, so use FrontBackSplit(headref,&a,&b); instead of FrontBackSplit(headref,a,b);.
As far as I can see, SortedMerge() should work (with a modified FrontBackSplit()). It is recursive, but not tail-recursive, so you might have problems with overflowing the stack for long lists. It isn't hard to make iterative, though.
You should make main() either int main(void) or int main(int, char**). You should return 0 for success.
My guess is that one of three things are breaking your code. When you Create() your lists, you do not get the lists you want. In just the right circumstances, with just the right compiler and function call configurations, however, you might get lucky (and maybe that is what you have seen). In that case, it might be the return in MergeSort(). Return head instead, there, that is probably what you want. If you have an empty list or a list of length one, you should return that list. So change return; to return head;. And if it isn't that either, it is probably because you recurse on random data in MergeSort(), because a and b aren't initialised in the recursion. They are uninitialised when you call FrontBackSplit() and the call doesn't change them, because they are passed by value and not reference. The change I listed above will fix that.
There might be more that I have overlooked, but at least those three issues are enough to break the code, each of them on their own, so it is a good place to start with debugging.

listing doubly linked list items C

I'm new to C.I am trying to create a doubly linked list where the data field is a structure. But when I output the elements, only the first field of the structure is correctly displayed.
struct n
{
int a;
int b;
};
typedef struct _Node {
struct n *value;
struct _Node *next;
struct _Node *prev;
} Node;
typedef struct _DblLinkedList {
size_t size;
Node *head;
Node *tail;
} DblLinkedList;
DblLinkedList* createDblLinkedList() {
DblLinkedList *tmp = (DblLinkedList*) malloc(sizeof(DblLinkedList));
tmp->size = 0;
tmp->head = tmp->tail = NULL;
return tmp;
}
void pushBack(DblLinkedList *list, struct n *value) {
Node *tmp = (Node*) malloc(sizeof(Node));
if (tmp == NULL) {
exit(3);
}
tmp->value = value;
tmp->next = NULL;
tmp->prev = list->tail;
if (list->tail) {
list->tail->next = tmp;
}
list->tail = tmp;
if (list->head == NULL) {
list->head = tmp;
}
list->size++;
}
void printInt(struct n *value) {
printf("%d, %d", value->a, value->b);
}
void printDblLinkedList(DblLinkedList *list, void (*fun)(struct n*)) {
Node *tmp = list->head;
while (tmp) {
fun(tmp->value);
tmp = tmp->next;
printf("\n");
}
}
So, I have a few questions. Did I declare the node value field correctly? Am I inserting the node at the end of the list correctly? Am I doing the output of doubly linked list items correctly? And where is my mistake and how to fix it?
Did I declare the node value field correctly?
That depends on what your intention was. In terms of storing a pointer to a struct n: yes.
Am I inserting the node at the end of the list correctly?
Yes.
Am I doing the output of doubly linked list items correctly?
Yes.
And where is my mistake and how to fix it?
The code works from my point-of-view but what can be misleading is how pushBack operates. pushBack takes the struct n pointer as-is and stores it in Node. You did not post the pushBack caller code but the current implementation can caused problems if the caller assumes that the struct n gets copied.
To illustrate that, consider the following:
struct n value;
value.a = 1;
value.b = 2;
pushBack(list, &value);
value.a = 3;
value.b = 4;
pushBack(list, &value);
By reusing the value, two linked list nodes will effectively contain the same values. Also, the inserted struct n pointer must remain valid throughout the lifetime of the list. So, inserting stack-allocated values (that will be deallocated later by leaving their scope) or freeing dynamically-allocated values too early might lead to incorrect values. As long as the caller knows that, this is not necessarily a problem.
There are usually 3 ways to handle memory ownership:
Data structure owns values (just like it owns nodes) and is responsible for freeing them
Data structure copies values and is responsible for freeing them
Caller owns values and is responsible for freeing them
For a linked list, there's lots of merit in the strategy #3, because a linked list can be created from existing values without any copying or ownership transfer which would most certainly require changes to existing code. That's basically what your code is doing at the moment.

C: From char array to linked list

I'm still learning how to program in C and I've stumbled across a problem.
Using a char array, I need to create a linked list, but I don't know how to do it. I've searched online, but it seems very confusing. The char array is something like this char arr[3][2]={"1A","2B","3C"};
Have a look at this code below. It uses a Node struct and you can see how we iterate through the list, creating nodes, allocating memory, and adding them to the linked list. It is based of this GeeksForGeeks article, with a few modifications. I reccommend you compare the two to help understand what is going on.
#include <stdio.h>
#include <stdlib.h>
struct Node {
char value[2];
struct Node * next;
};
int main() {
char arr[3][2] = {"1A","2B","3C"};
struct Node * linked_list = NULL;
// Iterate over array
// We calculate the size of the array by using sizeof the whole array and dividing it by the sizeof the first element of the array
for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); i++) {
// We create a new node
struct Node * new_node = (struct Node *)malloc(sizeof(struct Node));
// Assign the value, you can't assign arrays so we do each char individually or use strcpy
new_node->value[0] = arr[i][0];
new_node->value[1] = arr[i][1];
// Set next node to NULL
new_node->next = NULL;
if (linked_list == NULL) {
// If the linked_list is empty, this is the first node, add it to the front
linked_list = new_node;
continue;
}
// Find the last node (where next is NULL) and set the next value to the newly created node
struct Node * last = linked_list;
while (last->next != NULL) {
last = last->next;
}
last->next = new_node;
}
// Iterate through our linked list printing each value
struct Node * pointer = linked_list;
while (pointer != NULL) {
printf("%s\n", pointer->value);
pointer = pointer->next;
}
return 0;
}
There are a few things the above code is missing, like checking if each malloc is successful, and freeing the allocated memory afterwards. This is only meant to give you something to build off of!

Bubble-sorting doubly linked list

I have a problem with my bubble-sorting function for the doubly linked list.
It is working when I'm sorting the nodes in the singly linked way (only with ->next), but I can't make it work with ->prev pointers.
Here is the code I'm using:
void sort(int count)
{
struct data *tmp,*current,*nextone;
int i,j;
for(i=0;i<count;i++)
{
current = first;
for(j=0;j<count-1-i;j++ )
{
if(current->number > current->next->number)
{
nextone = current->next;
current->next = nextone->next;
nextone->next = current;
if(current == first)
{
first = nextone;
current = nextone;
}
else
{
current = nextone;
tmp->next = nextone;
}
}
tmp = current;
current = current->next;
}
}
}
And this is the structure I'm using (with the global variables for the first and last element of the list):
struct data
{
int id;
char name[20];
int number;
struct data *next;
struct data *prev;
};
struct data *first = NULL;
struct data *last = NULL;
Below logic would work.
I would follow similar algorithm... If you want to move the entire nodes...
struct data *before, *after;
if(current->number > current->next->number)
{
before = current->prev;
after = current->next;
if(before != NULL){
before->next = after;
}
current->next = after->next;
current->prev = after;
after->next = current;
after->previous = before;
}
Alternatively, you can simply swap the numbers in the nodes without bothering to move entire nodes, if sorting of the data is the purpose. You can expand the below logic to include swapping of both char array and id as well.
if(current->number > current->next->number)
{
int tempNum = current->number;
current->number = current->next->number;
current->next->number = tempNum;
}
You just need to sit down and think about it for a bit.
Assigning first? Well the previous must be null.
Assigning last? Next must be null.
Anything else you need to do a little swap-dance with previous & next of the elements you are swapping.
A much easier way (that will quickly become faster too for larger array sizes) is to allocate an array of pointers, fill those with pointers to the elements, qsort the array then do another pass to re-wire the pointers (and delete the temp array).
One easier way is just to copy the data of the node, you can swap the data but the pointer to the node.
if(current->number > current->next->number){
swap(current->id,current->next->id);
swap(current->name,current->next->name);
swap(current->number,current->next->number);
}
With your method, you never set the previous pointer at all. You can sort the double linked list as single list at first, and then traversal the list again to set all the prev pointer.
Of course, you can sort the double linked list at a time, but it's a little complex to implement. You should consider 4 nodes each step, i.e current, current->next, as well as current->prev and current->next->next. When you want to swap current and current->next,
you should set current->prev->next=current->next, current->next=current->next->next so on and so forth.

Resources