#include <stdio.h>
#include <stdlib.h>
#include <time.h>
main()
{
int ctr, inner, outer, didSwap, temp;
int nums[10];
time_t t;
srand(time(&t));
for (ctr = 0; ctr < 10; ctr++)
{
nums[ctr] = (rand() % 99) + 1;
}
puts("\nHere is the list before the sort:"); for (ctr=0; ctr < 10; ctr++) {
printf("%d\n", nums[ctr]); }
for(outer = 0; outer < 9; outer++) {
didSwap = 0;
for (inner = outer; inner < 10; inner++)
{
if (nums[inner] < nums[outer])
{
temp = nums[inner];
nums[inner] = nums[outer];
nums[outer] = temp;
didSwap = 1;
}
}
if (didSwap == 0)
{
break;
}
}
puts("\nHere is the list after the sort:"); for(ctr = 0; ctr < 10; ctr++) {
printf("%d\n", nums[ctr]);
}
return 0;
}
I don't understand this part:
for(outer = 0; outer < 9; outer++) {
didSwap = 0;
for (inner = outer; inner < 10; inner++) {
if (nums[inner] < nums[outer])
...
}
}
If outer = 0 and inner = outer then both inner and outer equal to 0. and if the loop FOR says if (nums[inner] < nums[outer])
then how can nums[0] can be smaller than nums[0] since both inner and outer = 0? Please help me to understand.
guys i think my text book code is faulty. what do you think?
now the prob is with the BREAK. Do u think its on a right place.
if (didSwap == 0) {
break; }
now the problem is what if the 1st two array values are in ascending order and rest of the element of NUMS[] are random, then after the 1st iteration of inner loop it will break the outer loop since the didSwap will still be equivalent to zero.
i tried to initialized the NUMS[] manually like this..
int nums[10]={4,6,8,65,47,74,21,22,65,36};
please have a look...thanks
1)
Here is pseudocode that will help you to understand:
FOR J=1 TO N-1 {
FOR I=1 TO N-J {
IF A[I]>A[I+1] THEN SWAP A[I],A[I+1]
NEXT I
}
NEXT J
}
2)
As for the Bubble sorting in process.. Here is a simple example:
1) At first we compare the first two elements.
If the 1st el. is bigger (or equal) than the next el. - we swap them.
If the 1st el. is smaller - we do nothing.
(The smallest elements will be closer to the top & biggets to the bottom)
Then we compare 2nd and 3rd elements, them 3rd and 4th etc.
Compare all the elements until the last in array.
/* In this cycle, the biggest element will go to the bottom. */
2) Then we "forget" the last (the biggest) element and repeat the same again.
3) Repeat 1) and 2) successively until the end.
/* After all, all the elements will be sorted now: */
/* from the smallest to the largest. */
EXAMPLE:
Suppose we have 4 elements: 8, 6, 2, 1. That's how we will sort them:
1st cycle:
8, 6, 2, 1
v v
8 is bigger than 6, so we swap them
6, 8, 2, 1
v v
8 is bigger than 2, so we swap them
6, 2, 8, 1
v v
8 is bigger than 1, so we swap them
6, 2, 1, 8
v
The biggest element is at the bottom now.
2nd cycle:
6, 2, 1, 8
v v
6 is bigger than 2, so we swap them
2, 6, 1, 8
v v
6 is bigger than 1, so we swap them
2, 1, 6, 8
v v
6 will always be smaller or equal to 8, so we use ...
for (inner = 0; inner < (N-outer); inner++)
^^^^^^^ ... this expression to avoid
unnecessary actions.
3rd cycle:
2, 1, 6, 8
v v
2 is bigger than 1, so we swap them
The are 4 elements but we do (4-1)= 3 cycles:
for(outer = 0; outer < (N-1); outer++)
^^^
3)
Now, imagine that N = 10, outer = J and inner = I:
for(J = 0; J < (N-1) ; J++) {
didSwap = 0;
for (I = 0; I < (N-J); I++)
{
if (nums[I] < nums[I + 1])// at the beginning, here J = 0 and I = 1;
{ // then J = 0 and I = 2 etc.
temp = nums[I]; // It compares the first element with the
nums[I] = nums[I + 1]; // othe ones and swaps them so more lightweight
nums[I + 1] = temp; // (smaller, light) element will move higher.
didSwap = 1; // Just like a bubble.
}
}
if (didSwap == 0)
{
break;
}
}
UPDATE:
4)
You can't break the sorting loop until it finishes!
Look at the following code. It does fit the Bubble-sorting pseudocode (at the top of this answer):
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define N 10 // Here you can change the number of elements that
// will be sorted.
int main()
{
int ctr, inner, outer, didSwap, temp;
int nums[N];
time_t t;
srand(time(&t));
for (ctr = 0; ctr < N; ctr++)
{
nums[ctr] = (rand() % 99) + 1; // Filling the elements with random
} // values from 1 to 99.
puts("\nHere is the list before the sort:");
for (ctr=0; ctr < N; ctr++) {
printf("%d\n", nums[ctr]);
}
didSwap = 0;
for(outer = 0; outer < (N-1); outer++) {
for (inner = 0; inner < (N-outer); inner++)
{
if (nums[inner] >= nums[inner + 1]) // notice that there is `>=`
{ // instead of `>`.
temp = nums[inner]; // This will exchange also
nums[inner] = nums[inner + 1]; // equal elements so the
nums[inner + 1] = temp; // sorting will work correctly.
}
}
didSwap = 1; // Change `didSwap` only once --> after all cycles
// and all swappings: changing it's value after each
// swapping is a waste of machine's resources.
}
/* I can't understand why do you want to use this variable, but here it is. */
printf(" >>> didSwap = %d <<<\n", didSwap);
puts("\nHere is the list after the sort:");
for(ctr = 0; ctr < N; ctr++) {
printf("%d\n", nums[ctr]);
}
return 0;
}
You're correct that in the first iteration of the inner loop that if condition will always be false.
That's inefficient, but it does not make the algorithm incorrect.
This would be better:
for (inner = outer+1; inner < 10; inner++)
Related
I am trying to learn the bubble sort algorithm in a book for C. I can't seem to understand in the code below how int outer and int inner link to which element of the nums array. Like how does inner become nums[0] while outer becomes nums[1] (if I'm correct), then progresses through the loop?
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main()
{
int ctr, inner, outer, didSwap, temp;
int nums[10];
time_t t;
srand(time(&t));
for (ctr = 0; ctr < 10; ctr++)
{
nums[ctr] = (rand() % 99) + 1;
}
puts("\n Here is the list before the sort: ");
for (ctr = 0; ctr < 10; ctr++)
{
printf("%i\n", nums[ctr]);
}
for (outer = 0; outer < 9; outer++)
{
didSwap = 0;
for (inner = outer; inner < 10; inner++)
{
if (nums[inner] < nums[outer])
{
temp = nums[inner];
nums[inner] = nums[outer];
nums[outer] = temp;
didSwap = 1;
}
}
if (didSwap == 0)
{
break;
}
}
puts("\n Here is the list after the sort: ");
for ( ctr = 0; ctr < 10; ctr++)
{
printf("%i\n", nums[ctr]);
}
return 0;
}
inner never becomes nums[0]. inner and outer are array indexes, so when inner is 0, nums[inner] is nums[0].
The code that performs the comparison and swapping never does that with inner and outer, it uses nums[inner] and nums[outer].
if (nums[inner] < nums[outer])
{
temp = nums[inner];
nums[inner] = nums[outer];
nums[outer] = temp;
didSwap = 1;
}
I am trying to learn the bubble sort algorithm in a book for C.
For starters if the presented code is indeed from a book then I advice to stop reading the book because it seems the author of the book is a low-qualified programmer.
The presented method is not the bubble sort method.
It looks like the selection sort method with redundant swaps.
And moreover the code contains a serious bug.
For example take an array like
int nums[] = { 0, 9, 8, 7, 6, 5, 4, 3, 2, 1 };
and the array will not be sorted!
What is the inner loop doing?
It travers the array after the current element nums[outer] and if it finds an element nums[inner] that is less than nums[outer] it swaps the elements and sets the flag didSwap to 1 (the flag means that some elements were swapped and the outer loop shall continue its iterations)
if (nums[inner] < nums[outer])
{
temp = nums[inner];
nums[inner] = nums[outer];
nums[outer] = temp;
didSwap = 1;
}
}
Otherwise if there are no swaps then the control exits the outer loop
if (didSwap == 0)
{
break;
}
However the selection sort method must continue its iteration even if for the current nums[outer] there was not found an element nums[inner] less than nums[outer].
Here is a demonstration program that shows that the presented sort method (that is not the bubble sort method) does not work.
#include <stdio.h>
int main( void )
{
int ctr, inner, outer, didSwap, temp;
int nums[3] = { 1, 3, 2 };
for (outer = 0; outer < 2; outer++)
{
didSwap = 0;
for (inner = outer; inner < 3; inner++)
{
if (nums[inner] < nums[outer])
{
temp = nums[inner];
nums[inner] = nums[outer];
nums[outer] = temp;
didSwap = 1;
}
}
if (didSwap == 0)
{
break;
}
}
puts("\n Here is the list after the sort: ");
for ( ctr = 0; ctr < 3; ctr++)
{
printf("%i\n", nums[ctr]);
}
}
The program output is
Here is the list after the sort:
1
3
2
As you can see the array was not sorted.:)
Minimal, reproducible example:
#include <stdio.h>
main() {
int ctr, inner, outer, didSwap, temp;
int nums[10] = {0, 1, 9, 7, 8, 4, 3, 5, 7, 10};
for (outer = 0; outer < 9; outer++) {
didSwap = 0;
for (inner = outer; inner < 10; inner++) {
if (nums[inner] < nums[outer]) {
temp = nums[inner];
nums[inner] = nums[outer];
nums[outer] = temp;
didSwap = 1;
}
}
if (didSwap == 0) {
break;
}
}
puts("\nHere is the list after the sort:");
for (ctr = 0; ctr < 10; ctr++) {
printf("%d\n", nums[ctr]);
}
return (0);
}
Book code:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
main() {
int ctr, inner, outer, didSwap, temp;
int nums[10];
time_t t;
// If you don't include this statement, your program will always
// generate the same 10 random numbers
srand(time( & t));
// The first step is to fill the array with random numbers
// (from 1 to 100)
for (ctr = 0; ctr < 10; ctr++) {
nums[ctr] = (rand() % 99) + 1;
}
// Now list the array as it currently is before sorting
puts("\nHere is the list before the sort:");
for (ctr = 0; ctr < 10; ctr++) {
printf("%d\n", nums[ctr]);
}
// Sort the array
for (outer = 0; outer < 9; outer++) {
didSwap = 0; //Becomes 1 (true) if list is not yet ordered
for (inner = outer; inner < 10; inner++) {
if (nums[inner] < nums[outer]) {
temp = nums[inner];
nums[inner] = nums[outer];
nums[outer] = temp;
didSwap = 1;
}
}
if (didSwap == 0) {
break;
}
}
// Now list the array as it currently is after sorting
puts("\nHere is the list after the sort:");
for (ctr = 0; ctr < 10; ctr++) {
printf("%d\n", nums[ctr]);
}
return (0);
}
Tweaked book code:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
main() {
int ctr, inner, outer, didSwap, temp;
int nums[10];
time_t t;
srand(time( & t));
nums[0] = 0; //set the first element of the array to the lowest value possible
for (ctr = 1; ctr < 10; ctr++) {
nums[ctr] = (rand() % 99) + 1;
}
puts("\nHere is the list before the sort:");
for (ctr = 0; ctr < 10; ctr++) {
printf("%d\n", nums[ctr]);
}
for (outer = 0; outer < 9; outer++) {
didSwap = 0;
for (inner = outer; inner < 10; inner++) {
if (nums[inner] < nums[outer]) {
temp = nums[inner];
nums[inner] = nums[outer];
nums[outer] = temp;
didSwap = 1;
}
}
if (didSwap == 0) {
break;
}
}
puts("\nHere is the list after the sort:");
for (ctr = 0; ctr < 10; ctr++) {
printf("%d\n", nums[ctr]);
}
return (0);
}
From the book,
The next program sorts a list of 10 numbers. The numbers are randomly
generated using rand(). The bubble sort routine is little more than a
nested for loop. The inner loop walks through the list, swapping any
pair of values that is out of order down the list. The outer loop
causes the inner loop to run several times (one time for each item in
the list).
An added bonus that is common to many improved bubble sort
routines is the testing to see whether a swap took place during any
iteration of the inner loop. If no swap took place, the outer loop
finishes early (via a break statement). Therefore, if the loop is
sorted to begin with, or if only a few passes are needed to sort the
list, the outer loop doesn’t have to finish all its planned
repetitions.
The second paragraph has to do with didSwap as it determines whether or not the program finishes early, if it's equal to zero.
The first example (from top to bottom) yields an unsorted array because no integer is less than the first element 0 in the array int nums[10] and so nums[inner] < 0 is false for every inner from 0 to 9 (inclusive). As a consequence, didSwap remains equal to zero, which finishes the program early: if (didSwap == 0) { break;}. However, according to the book, this means that the array was already sorted, but this is not the case.
Have I missed something? If not, I would like to know how would you modify the code to allow for what the book says in the second paragraph: "If the loop is sorted to begin with, or if only a few passes are needed to sort the list, the outer loop doesn’t have to finish all its planned repetitions." I haven't been able to think of something.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
main()
{
int ctr, inner, outer, didSwap, temp;
int nums[10];
time_t t;
srand(time(&t));
for (ctr = 0; ctr < 10; ctr++) {
nums[ctr] = (rand() % 99) + 1;
}
printf("\nHere is the list before the sort:\n");
for (ctr = 0; ctr < 10; ctr++) {
printf("%3d", nums[ctr]);
}
// Sorting the array
for (outer = 0; outer < 9; outer++) {
didSwap = 0;
for (inner = outer + 1; inner < 10; inner++) {
if (nums[inner] < nums[outer]) {
temp = nums[inner];
nums[inner] = nums[outer];
nums[outer] = temp;
didSwap = 1;
}
}
if (didSwap == 0) {
break;
}
}
printf("\n\nHere is the list after sorting:\n");
for (ctr = 0; ctr < 10; ctr++) {
printf("%3d", nums[ctr]);
}
printf("\n");
return 0;
}
It works most of the times but sometimes doesn't sort properly and sometimes doesn't sort at all.
P.S. If the code is incorrect then why does it work 85% of the times.
Snapshot of error
Your code is a wrong implementation of the bubble sort.
If the first element of the array is the smaller one as the example in your question the code
if (didSwap == 0) {
break;
}
breaks the loops at the first turn and nothing is sort.
A test similar to the one for didSwap exists in a bubble sort, but the implementation is different, it does not do if (nums[inner] < nums[outer]) but compare each element with the next.
If the code is incorrect then why does it work 85% of the times
I don't know from where these 85% comes (and is very probably false), of course all depends on the values in the array, but when nums[outer]is smaller than all the elements having a greater index your program stops, and the elements having a greater index are not sorted. In the example in your question the very first element is the smaller of the array so nothing at all is sort.
So two possibilities :
to remove all concerning didSwap
to implement a bubble sort
to have a bubble sort modify your internal loop to have for instance :
for (inner = outer + 1; inner < 8; inner++) {
if (nums[inner] > nums[inner + 1]) {
temp = nums[inner];
nums[inner] = nums[inner + 1];
nums[inner + 1] = temp;
didSwap = 1;
}
}
for instance to use the values you give in your question :
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main()
{
int ctr, inner, outer, didSwap, temp;
#if 1
int nums[10] = { 4, 6, 25, 9, 60, 59, 44, 65, 59, 90};
#else
int nums[10];
time_t t;
srand(time(&t));
for (ctr = 0; ctr < 10; ctr++) {
nums[ctr] = (rand() % 99) + 1;
}
#endif
puts("\nHere is the list before the sort:");
for (ctr = 0; ctr < 10; ctr++) {
printf("%3d", nums[ctr]);
}
// Sorting the array
for (outer = 0; outer < 9; outer++) {
didSwap = 0;
for (inner = outer + 1; inner < 8; inner++) {
if (nums[inner] > nums[inner + 1]) {
temp = nums[inner];
nums[inner] = nums[inner + 1];
nums[inner + 1] = temp;
didSwap = 1;
}
}
if (didSwap == 0) {
break;
}
}
puts("\n\nHere is the list after sorting:");
for (ctr = 0; ctr < 10; ctr++) {
printf("%3d", nums[ctr]);
}
putchar('\n');
return 0;
}
Compilation and execution :
pi#raspberrypi:/tmp $ gcc -Wall c.c
pi#raspberrypi:/tmp $ ./a.out
Here is the list before the sort:
4 6 25 9 60 59 44 65 59 90
Here is the list after sorting:
4 6 9 25 44 59 59 60 65 90
pi#raspberrypi:/tmp $
For some reason, you break if no swap is done for any particular element, thus leaving the other elements unsorted:
if (didSwap == 0) {
break;
}
You need to remove the above conditional to make it work and sort all the elements. There is no need of such conditional in the standard selection sort algorithm as well.
You are breaking the outer loop when there is no swap. This will not gonna work so remove the didSwap and remove the below code
if (didSwap == 0) {
break;
}
and the program should work fine.
Since this year I'm starting studying C programming at university.
In particular today I was trying to understand the insertion sort.
I wrote this code that is perfectly working:
void insertionSort (int v[], int s)
{
int i;
int j;
int value;
for (i = 1; i < s; i++)
{
value = v[i];
for (j = i - 1; (j >= 0) && (value < v[j]); j --)
{
v[j + 1] = v[j];
}
v[j + 1] = value; // why v[j+1]?
}
}
My question is about the last code line: v[j + 1] = value. If I understand correctly, j (that decreases every time), at the end of the for cycle, has a value of -1 and that's why is correct to write v[j + 1] = value.
Am I right or am I missing something? Really thanks for anybody who wants to help me by explaining me better.
The way you have your code setup right now, you need v[j + 1] because j will always be one before where you want to insert.
For example:
int v[6] = {1, 34, 2, 50, 4, 10}
s = sizeof(v) / sizeof(v[0]) = 6
Stepping through your code:
i = 1, j = 0
value = v[i] = 34
34 < 1 is false so it doesn't go into the inner
for loop
v[j + 1] = 34 which is right where 34 should be
Looping your entire code a second time: value = 2, j = 1, i = 2
Both conditions are met where j = 1 && 2 < 34 and you go into your inner loop
Since you already stored v[2] earlier when you did value = v[i], v[2] = 34 at this point is where you decrease j by 1 making j = 0
Looking at your array, it looks like this:
1, 34, 34
The inner for loop will try to loop again but fail the second check
At this point, j is 0 and when you do v[j + 1] = value, you're storing value (2) in its proper place.
Your array at this point looks like 1, 2, 34
So again, the significance of v[j + 1] is to insert in the correct place. If the value is already in the correct place than you swap with itself.
This is the process of Insertion Sort. It will swap if the numbers are not ordered.
Over here you can find an visualized example: https://visualgo.net/en/sorting
Here you have an example in C:
#include <stdio.h>
int main()
{
int n, array[1000], c, d, t;
printf("Enter number of elements\n");
scanf("%d", &n);
printf("Enter %d integers\n", n);
for (c = 0; c < n; c++) {
scanf("%d", &array[c]);
}
// Insertion Sort
for (c = 1 ; c <= n - 1; c++) {
d = c;
while ( d > 0 && array[d] < array[d-1]) {
t = array[d];
array[d] = array[d-1];
array[d-1] = t;
d--;
}
}
printf("Sorted list in ascending order:\n");
for (c = 0; c <= n - 1; c++) {
printf("%d\n", array[c]);
}
return 0;
}
mark first element as sorted
for each unsorted element
'extract' the element
for i = lastSortedIndex to 0
if currentSortedElement > extractedElement
move sorted element to the right by 1
else: insert extracted element
I've written the function which bubble-sorts some given array, and stops execution when the array is already sorted.
int sort(int *arr, int size) {
int i, j, temp, st = 1, count = 0;
for(i = 0; (i < size - 1) && (st == 1); i++)
{
st = 0;
for(j = 0; j < size - 1; j++)
{
if(arr[j] < arr[j + 1])
{
temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
st = 1;
}
count++;
}
}
return count;
}
As you can see, the loop should be broken when the array is sorted before size^2 move.
However, something is wrong, and the count variable is always size * size, no matter what array I pass, even {1, 2, 3, 4, 5} gives the same results.
What is wrong?
With the condition
if(arr[j] < arr[j + 1])
you are sorting the array in descending order. So if you pass it [5, 4, 3, 2, 1], you'll get a value of less than size*size.
Note that each iteration of the outer loop moves one element to its final place at the end of the array, so you can cut down the inner loop to run only
for(j = 0; j < size - 1 - i; j++)
If we run
#include <stdio.h>
int sort(int *arr, int size) {
int i, j, temp, st = 1, count = 0;
for(i = 0; (i < size - 1) && (st == 1); i++)
{
st = 0;
for(j = 0; j < size - 1; j++)
{
if(arr[j] < arr[j + 1])
{
temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
st = 1;
}
count++;
}
}
return count;
}
int main(void) {
#ifdef ASCENDING
int ar[] = { 1, 2, 3, 4, 5 };
#else
int ar[] = { 5, 4, 3, 2, 1 };
#endif
int i, ct = sort(ar, sizeof ar / sizeof ar[0]);
printf("%d\n",ct);
for(i = 0; i < (int)(sizeof ar / sizeof ar[0]); ++i) {
printf("%d ", ar[i]);
}
printf("\n");
return 0;
}
compiled without ASCENDING defined, the output is
4
5 4 3 2 1
thus the outer loop breaks after the first iteration because the array is already sorted as desired. When compiled with -DASCENDING, the array is originally in ascending order and needs the complete cycle to become sorted, i.e. the output is
16
5 4 3 2 1
(with the count being reduced to 10 if the inner loop runs only for j < size - 1 - i).