C code implementing bubble sort for linked list isn't working - c

I am trying to apply bubble sort on linklist. for that I have implemented my own list but the code isn't working as it somehow isn't printing any value when all of the linklist values are printed.
The course I was writing code for required me to write everything from scratch. I wrote a bubble sort function which isn't working as it should, It is somehow tempering the root due to which I am not able to print all of the values of the linklist.
I also tried to print string "values swapped" to understand how many times is the loop running, turns out it is running the number of times it should run. but doing something due to which I can't print the values from the root.
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <stdbool.h>
typedef struct Node
{
int value;
struct Node *next;
} Node;
Node *insert(Node *root, int val)
{
Node *new = (Node *)malloc(sizeof(Node));
new->value = val;
new->next = NULL;
if (root == NULL)
{
root = new;
return root;
}
while (root->next != NULL)
{
root = root->next;
}
root->next = new;
return NULL;
}
void swap(Node *n1, Node *n2)
{
int temp = n1->value;
n1->value = n2->value;
n2->value = temp;
}
void print(Node *root)
{
if (root == NULL)
return;
printf("%d ", root->value);
print(root->next);
}
void bubbleSort(Node *root)
{
bool toSwap = true;
Node *trav = root;
while (toSwap)
{
toSwap = false;
while (trav != NULL)
{
if (trav->value > trav->next->value)
{
swap(trav, trav->next);
printf("Values Swapped \n");
toSwap = true;
}
trav = trav->next;
}
}
}
int main(void)
{
Node *root = NULL;
root = insert(root, 4);
insert(root, 1);
insert(root, 5);
insert(root, 3);
bubbleSort(root);
print(root);
return 0;
}

Your code runs in O(n) time, since trav moves forward at every iteration and the algorithm terminates when trav has reached the end of the list. However, Bubble Sort is a O(n^2) time algorithm.
You need to use two pointers. Let's call the second pointer trav_2. The first pointer (trav) simply acts as a counter to make sure that the second pointer (trav_2) iterates through the list performing the necessary swaps n times. If you replace your while loop with the following logic, it should work fine:
while (trav!=NULL)
{
toSwap = false;
Node *trav_2 = root;
while (trav_2 != NULL && trav_2->next!=NULL)
{
if (trav_2->value > trav_2->next->value)
{
swap(trav_2, trav_2->next);
printf("Values Swapped \n");
toSwap = true;
}
trav_2 = trav_2->next;
}
trav = trav->next;
}
I have also fixed some pointer dereferencing errors you had in your code (the ones others have mentioned). However, fixing them wasn't enough. The logic was flawed too.

Fixing the existing code has already been done by Harsh. I'm going to show you how this is done by pure pointer juggling rather than swapping datum across nodes. Normally that is the purpose of this exercise. Imagine an enormous data payload held within each node that makes it obtrusive to copy. You don't have to if you just jostle the pointers to rearrange the list.
For each enumeration the "largest" element will bubble to the end. it is pruned from there and pushed on to the head of a new list. When the algorithm is done one of two things will have transpired:
We ran out of nodes. OR
We ejected early due to noswap-optimization.
The first of these is trivial. We already have all the nodes and they're already sorted. The latter complicates things because we still have two sorted lists: one is the list of items we've pruned thus far as we push-built our sorted result, the other is the remaining list that we detected as already-sorted and ejected the sorting loop. Fortunately, due to the manner in which we tracked the last node pointer in remaining source list, it makes linking them easy and we'll have our final result.
Finally, because root can change, the algorithm requires the new root be returned from the function. That, in turn, requires a change in main. This is not specific to the aforementioned algorithm. It would have to be done regardless as a separate, but important, bug fix.
The sorting implementation appears below:
Node *bubbleSort(Node *root)
{
Node *result = NULL;
Node **pp;
bool swapped = (root != NULL);
while (swapped)
{
// reset swap state
swapped = false;
pp = &root;
while (*pp && (*pp)->next)
{
// compare the two node values
if ((*pp)->next->value < (*pp)->value)
{
Node *p = *pp;
*pp = (*pp)->next;
p->next = (*pp)->next;
(*pp)->next = p;
swapped = true;
}
pp = &(*pp)->next;
}
// pp holds the address of the pointer pointing to
// the last node in the source list. So, we...
// 1. prune off the end node.
// 2. terminate the source list
// 3. push the pruned node on to the front of
// the result list where it belongs.
Node *p = *pp;
*pp = NULL;
p->next = result;
result = p;
// TODO: fun thing here. print both lists (result and root)
}
// the above loop could have exited early, leaving root
// holding the sorted low half of the list. the *last*
// pointer in that list is addressed by pp, so we can
// just link the rest of the list we already pruned to
// that end and we're done.
*pp = result;
return root;
}
The change in main is likewise below:
int main(void)
{
Node *root = insert(root, 4);
insert(root, 1);
insert(root, 5);
insert(root, 3);
root = bubbleSort(root);
print(root);
return 0;
}
And finally, the result:
1 3 4 5
Worth noting: bubble-sort is already dreadful enough. It is a terrible fit for nearly all sorting purposes, and especially for linked lists, where the ideal sorting mechanic would be merge-sort. But for academic purposes it makes for an interesting exercise, especially if you embrace the challenge of doing it exclusively with pointer jostling; not datum swapping.
An Interesting View
Modifying the code to do the following:
Generate a random shuffle of the sequence 1...30
Do the sort as shown above, but print the source and result lists after each iteration.
the results show how the pruning, pushing, and final fix up happen. The original shuffled list is:
11 28 16 6 12 23 13 1 20 14 27 3 2 7 21 4 8 30 19 15 22 17 26 29 24 9
Printing each list (the remaining source list and the result we're building), the outcome looks like this:
root: 11 16 6 12 23 13 1 20 14 27 3 2 7 21 4 8 28 19 15 22 17 26 29 24 9 5 18 25 10
result: 30
root: 11 6 12 16 13 1 20 14 23 3 2 7 21 4 8 27 19 15 22 17 26 28 24 9 5 18 25 10
result: 29 30
root: 6 11 12 13 1 16 14 20 3 2 7 21 4 8 23 19 15 22 17 26 27 24 9 5 18 25 10
result: 28 29 30
root: 6 11 12 1 13 14 16 3 2 7 20 4 8 21 19 15 22 17 23 26 24 9 5 18 25 10
result: 27 28 29 30
root: 6 11 1 12 13 14 3 2 7 16 4 8 20 19 15 21 17 22 23 24 9 5 18 25 10
result: 26 27 28 29 30
root: 6 1 11 12 13 3 2 7 14 4 8 16 19 15 20 17 21 22 23 9 5 18 24 10
result: 25 26 27 28 29 30
root: 1 6 11 12 3 2 7 13 4 8 14 16 15 19 17 20 21 22 9 5 18 23 10
result: 24 25 26 27 28 29 30
root: 1 6 11 3 2 7 12 4 8 13 14 15 16 17 19 20 21 9 5 18 22 10
result: 23 24 25 26 27 28 29 30
root: 1 6 3 2 7 11 4 8 12 13 14 15 16 17 19 20 9 5 18 21 10
result: 22 23 24 25 26 27 28 29 30
root: 1 3 2 6 7 4 8 11 12 13 14 15 16 17 19 9 5 18 20 10
result: 21 22 23 24 25 26 27 28 29 30
root: 1 2 3 6 4 7 8 11 12 13 14 15 16 17 9 5 18 19 10
result: 20 21 22 23 24 25 26 27 28 29 30
root: 1 2 3 4 6 7 8 11 12 13 14 15 16 9 5 17 18 10
result: 19 20 21 22 23 24 25 26 27 28 29 30
root: 1 2 3 4 6 7 8 11 12 13 14 15 9 5 16 17 10
result: 18 19 20 21 22 23 24 25 26 27 28 29 30
root: 1 2 3 4 6 7 8 11 12 13 14 9 5 15 16 10
result: 17 18 19 20 21 22 23 24 25 26 27 28 29 30
root: 1 2 3 4 6 7 8 11 12 13 9 5 14 15 10
result: 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
root: 1 2 3 4 6 7 8 11 12 9 5 13 14 10
result: 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
root: 1 2 3 4 6 7 8 11 9 5 12 13 10
result: 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
root: 1 2 3 4 6 7 8 9 5 11 12 10
result: 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
root: 1 2 3 4 6 7 8 5 9 11 10
result: 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
root: 1 2 3 4 6 7 5 8 9 10
result: 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
root: 1 2 3 4 6 5 7 8 9
result: 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
root: 1 2 3 4 5 6 7 8
result: 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
root: 1 2 3 4 5 6 7
result: 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
The final result is as expected:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30

Change your inner while loop to this:
while (trav != NULL && trav->next != NULL) {
if (trav->value > trav->next->value) {
printf("Swapping values %d %d\n", trav->value, trav->next->value);
swap(trav, trav->next);
toSwap = true;
}
trav = trav->next;
}
It corrects the NULL pointer dereferencement.
You'll see why it doesn't work by clearly showing what is being swapped.
That being said, you should rather do what is mentioned in the second comment.

Related

A problem with fscanf() in c , overwriting other variables

I'm traying to read from a file two things :
1- a list of integers(on the top of the file) in to an array of integers inputs[]
2- 3 matrixes 5x5 etch into an array of array of array boards[][][]
the firs part works properly but when the 2 part finished some how the inputs[] change values
The code :
void loadfile(const char* filepath,int *inputs ,int boards [nboards][size][size]){
FILE *inp=fopen(filepath,"r");
//loading the marked numbers
for(int i=0;i<4;i++){
fscanf(inp,"%d",inputs+i);
//to show that inputs reseve the the right values at the start
printf("%d ",*(inputs+i));
fseek(inp,ftell(inp)+1,SEEK_SET);
}
printf("\n");
//loaing the boards
for(int n=1;n<=nboards;n++){
for(int i=0;i<size;i++)
for(int j=0;j<size;j++){
fscanf(inp,"%d",&boards[n][i][j]);
printf("%d ",boards[n][i][j]);
}
printf("\n");
}
fclose(inp);
}
int main(){
int inputs[4]={};
int boards[nboards][size][size]={};
loadfile("inputs.txt",inputs,boards);
for(int i=0;i<4;i++)
printf("%d ",*(inputs+i));
}
The file :
7,4,9,5
22 13 17 11 0
8 2 23 4 24
21 9 14 16 7
6 10 3 18 5
1 12 20 15 19
3 15 0 2 22
9 18 13 17 5
19 8 7 25 23
20 11 10 24 4
14 21 16 12 6
14 21 17 24 4
10 16 15 9 19
18 8 23 26 20
22 11 13 6 5
2 0 12 3 7
The output:
7 4 9 5
22 13 17 11 0 8 2 23 4 24 21 9 14 16 7 6 10 3 18 5 1 12 20 15 19
3 15 0 2 22 9 18 13 17 5 19 8 7 25 23 20 11 10 24 4 14 21 16 12 6
14 21 17 24 4 10 16 15 9 19 18 8 23 26 20 22 11 13 6 5 2 0 12 3 7
21 17 24 4

How do I perform shell sort using sequence {3,2,1}?

Suppose I have an array:
30 20 29 19 28 18 27 17 26 16 25 15 24 14 23 13 22 12 21 11
I am not understanding how to do the shell sort using sequence 3:
Would I simply do this:
30 20 29 19 28 18 27 17 | 26 16 25 15 24 14 |23 13 22 12 21 11
Where I split it into 3 parts and sort the respective parts? And then do the same with 2 sorting after, except split into halves? What is the right way to do this? Can someone please explain?
If you look at your array and number the locations
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
30 20 29 19 28 18 27 17 26 16 25 15 24 14 23 13 22 12 21 11
In a shell sort, what you do is start with a skip number (in your case 3) so to make the first "list" you take a number and skip. With 3 this would be 1st, 4th, 7th etc.
So you would have a list of
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
30 19 27 16 24 13 21
and a second list of
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
20 28 17 25 14 22 11
The 3rd list is the remaining items.
For the next round you do it with one less... so items at odd number locations and items at even number locations.
In response to comment below
A Shell sort is an in-place sort — that means you don't remove the items to new lists or create any new data structures. You are using the array to "treat" items which are "far apart" in terms of array locations as next to each other. You don't actually make new lists or new arrays (that is why I showed my diagrams as I did); you just look at these locations.
Why?
Because it means that when you start (for example with 3) you are moving stuff farther) -- eg the 13 that starts at location 16 gets moved to location 1 in the first pass. Then as you reduce the number you start doing more local changes. This means you gain an advantage over a typical bubble sort. Still not good — but MUCH better than a bubble sort.

Create matrix of some repeating numbers

EN = 10;
etable = [1,2,3,4,5,6;
4,5,6,7,8,9;
7,8,9,10,11,12;
10,11,12,13,14,15;
13,14,15,16,17,18;
16,17,18,19,20,21;
19,20,21,22,23,24;
22,23,24,25,26,27;
25,26,27,28,29,30;
28,29,30,31,32,33];
Is it possible to make a for loop in which I just change the EN value and it automatically creates etable? Because I have to make EN 50 so it'll not be good to write 50 lines in etable.
I tried in this way:
EN = 10;
c = 1:EN;
nodes = zeros(size(c',1),2);
for i = 1:length(c)
nodes(i,1) = i;
nodes(i,2) = i+1;
end
etable = zeros(size(c',1),6);
for i = 1:size(nodes,1)
etable(i,1) = 2*nodes(i,1)-1;
etable(i,2) = 2*nodes(i,1);
etable(i,3) = 2*nodes(i,1)+1;
etable(i,4) = 2*nodes(i,2);
etable(i,5) = 2*nodes(i,2)+1;
etable(i,6) = 2*nodes(i,2)+2;
end
You can use implicit expansion implicitly (introduced in MATLAB R2016b) or explicitly by using MATLAB's bsxfun to create that matrix:
% Parameters
EN = 10;
n = 6;
step = 3;
% Matrix (implict expansion, MATLAB >= R2016b)
etable = (0:step:EN*step-1).' + (1:n)
% Matrix (bsxfun, MATLAB < R2016b)
etable_legacy = bsxfun(#plus, (0:step:EN*step-1).', (1:n))
For the given parameter set, the outputs are:
etable =
1 2 3 4 5 6
4 5 6 7 8 9
7 8 9 10 11 12
10 11 12 13 14 15
13 14 15 16 17 18
16 17 18 19 20 21
19 20 21 22 23 24
22 23 24 25 26 27
25 26 27 28 29 30
28 29 30 31 32 33
etable_legacy =
1 2 3 4 5 6
4 5 6 7 8 9
7 8 9 10 11 12
10 11 12 13 14 15
13 14 15 16 17 18
16 17 18 19 20 21
19 20 21 22 23 24
22 23 24 25 26 27
25 26 27 28 29 30
28 29 30 31 32 33
You can change EN (number of rows), the "number of columns" n and/or the "step between rows" step.
Hope that helps.

Matlab: repeat and concatenate rows and cols into new array

I have two 4-by-4 arrays:
a1 = [ 1 2 3 4; 5 6 7 8; 9 10 11 12; 13 14 15 16 ]
a2 = [ 17 18 19 20; 21 22 23 24; 25 26 27 28; 29 30 31 32 ]
I need to create 16-by-8 array C:
1 2 3 4 17 18 19 20
1 2 3 4 21 22 23 24
1 2 3 4 25 26 27 28
1 2 3 4 29 30 31 32
5 6 7 8 17 18 19 20
5 6 7 8 21 22 23 24
5 6 7 8 25 26 27 28
5 6 7 8 29 30 31 32
9 10 11 12 17 18 19 20
9 10 11 12 21 22 23 24
9 10 11 12 25 26 27 28
9 10 11 12 29 30 31 32
13 14 15 16 17 18 19 20
13 14 15 16 21 22 23 24
13 14 15 16 25 26 27 28
13 14 15 16 29 30 31 32
The left half (from 1st to 4th column) of the result array C should repeat 4 times i-th row of the array a1, the right half (from 5th to 8th column) should repeat 4 times the array a2.
Below is my code.
p=4
n=4
for i=1:n
b=n*i;
a=n*(i-1)+1;
for j=1:p
for k=a:b
C(k,j)=a1(i,j);
end;
end;
end;
for i=1:n
b=n*i;
a=n*(i-1)+1;
for j=p+1:2*p
l=1;
for k=a:b
C(k,j)=a2(l,j-p);
l=l+1;
end;
end;
end;
C;
size_C=size(C)
Question. Is it possible to create result array C without for-loop? Which functions can I use?
Yes it's possible.
One way of doing it is by using kron and repmat
C = [ kron(a1, ones(4,1)) repmat(a2, 4, 1)]
Perhaps the 4 should be derived from the size of one of the matrixes
You can use ndgrid to generate the row indices and then concatenate:
[ii, jj] = ndgrid(1:size(a2,1), 1:size(a1,1));
C = [a1(jj,:) a2(ii,:)];
With focus on performance, here's one using reshape and repmat -
% Store sizes
M = size(a1,1);
N = size(a2,1);
% Get the replicated version for a1 and a2 separately
parte1 = reshape(repmat(reshape(a1,1,M,[]),[N,1,1]),M*N,[])
parte2 = repmat(a2,[M,1]);
% Do columnar concatenatation for final output
out = [parte1 parte2]
Sample run on a generic case -
a1 = % 3 x 4 array
5 2 6 9
7 4 7 6
9 8 6 1
a2 = % 2 x 5 array
7 7 1 9 2
6 8 8 7 9
out =
5 2 6 9 7 7 1 9 2
5 2 6 9 6 8 8 7 9
7 4 7 6 7 7 1 9 2
7 4 7 6 6 8 8 7 9
9 8 6 1 7 7 1 9 2
9 8 6 1 6 8 8 7 9

Circularly shifting a vector

I have a vector which is like
x = [20 11 12 13 14 15 16 17 18 19]
I would like to shift the vector values as given
if (i = 1)
X = [11 12 13 14 15 16 17 18 19 20]
if (i = 2)
X = [12 13 14 15 16 17 18 19 20 11]
if (i = 3)
X = [13 14 15 16 17 18 19 20 11 12]
At present I am using a for loop to do this, but it takes a lot of time
x = [20 11 12 13 14 15 16 17 18 19];
in = x;
C1 = x;
for lt = 1:1:length(in)
C1 = x ;
if (lt > 1)
for tt = 1:1:lt-1
swap = C1(1);
for pt = 1:1:length(in)-1
C1(pt) = C1(pt+1);
end
C1(length(in)) = swap;
end
end
disp(C1);
end
Could some one please suggest me a faster algorithm?
Let s denote the number of positions you want to shift. You can use circshift:
x_shifted = circshift(x, [1 -s]);
The second argument is [1 -s] because you want to shift s positions to the left in the second dimension (columns).
You can also do it manually with mod:
x_shifted = x(mod((1:numel(x))+s-1, numel(x))+1);
circshift is the way to go but you could also do it with pretty simple indexing:
x_shifted = x([(i+1):end , 1:(i-1)])
This however assumes that 1 < i && i < length(x).
You could pre-calculate all C1's in one go (vectorized manner) before the start of the loop(s) and use their values inside the loop(s) directly with indexing alone and thus save time on calculating them -
N = numel(x);
C1_all = x(mod(bsxfun(#plus,[0:N-1]',0:N-1),N)+1)
Code run for given x -
C1_all =
20 11 12 13 14 15 16 17 18 19
11 12 13 14 15 16 17 18 19 20
12 13 14 15 16 17 18 19 20 11
13 14 15 16 17 18 19 20 11 12
14 15 16 17 18 19 20 11 12 13
15 16 17 18 19 20 11 12 13 14
16 17 18 19 20 11 12 13 14 15
17 18 19 20 11 12 13 14 15 16
18 19 20 11 12 13 14 15 16 17
19 20 11 12 13 14 15 16 17 18
I can also suggest using hankel. You can use hankel to generate a set of indices that you would use to index into x where each row gives you the circular shift amount you're looking for. Something like this:
x = [20 11:19];
c = x(hankel([1:numel(x)], [numel(x) 1:numel(x)-1]))
c =
20 11 12 13 14 15 16 17 18 19
11 12 13 14 15 16 17 18 19 20
12 13 14 15 16 17 18 19 20 11
13 14 15 16 17 18 19 20 11 12
14 15 16 17 18 19 20 11 12 13
15 16 17 18 19 20 11 12 13 14
16 17 18 19 20 11 12 13 14 15
17 18 19 20 11 12 13 14 15 16
18 19 20 11 12 13 14 15 16 17
19 20 11 12 13 14 15 16 17 18

Resources