My quicksort implementation gives wrong result - c

today I've been working on Quicksort algorithm implementation in C.
I thought that I've fully understood the issue, but after few attempts, the results weren't the same as I expected. I ask you for help in finding problem, because I can't find it on myself, I've even tried to look at another implementations in internet, and rewriting my functions, but nothing worked.
My code:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
void swap(int *x, int *y)
{
int temp = *y;
*x = *y;
*y = temp;
}
void printArray(int arr[], int size)
{
for(int i = 0; i < size; i++)
{
printf("%d ", arr[i]);
}
printf("\n");
}
int partition(int arr[], int low, int high)
{
int pivot = arr[high];
int i = (low - 1);
for(int j = low; j <= high-1; j++)
{
if(arr[j] <= pivot)
{
i++;
swap(&arr[i], &arr[j]);
}
}
swap(&arr[i+1], &arr[high]);
return(i+1);
}
void quickSort(int arr[], int low, int high)
{
if(low < high)
{
int pi = partition(arr, low, high);
quickSort(arr, low, pi-1);
quickSort(arr, pi + 1, high);
}
}
int main()
{
srand(time(NULL));
int arr[10];
for(int i = 0; i < 10; i++)
{
arr[i] = rand()%200 - 100;
}
printArray(arr, 10);
quickSort(arr, 0, 9);
printArray(arr, 10);
return 0;
}
Examplatory results:
-57 4 -30 -23 25 -67 83 26 -51 14
-67 -67 -51 -67 -51 -51 14 -51 14 14

The only problem with your quick-sort is that the swap function is not implemented correctly.
The correct implementation should be something like:
void swap(int *x, int *y) {
int temp = *x;
*x = *y;
*y = temp;
}
You may be interested in looking at some other quick-sort variant, for that see this.
A humble suggestion: Use Randomized Quick sort: It would also be better if you don't always select the last element as your pivot (what you can do here is just before starting to sort select any random element and then swap it with the last element of your array. Using this strategy you don't have to make much changes in your existing code) This selection of random element as pivot is much better. See this link for more details.

Related

Swap is not done between 2 integers in array in C language

I'm implementing Quick Sort Algorithm in C language, in which at only one particular interchange of 2 values arr[i] and pivot is not being done properly, else all the swapping is done accurately, I have debugged too and tried to understand what is the problem/mistake, maybe it is a logical error.
Here's the code:
#include <stdio.h>
void printArr(int arr[], int n)
{
for (int i = 0; i < n; i++)
printf("%d ", arr[i]);
printf("\n");
}
void swap(int *a, int *b)
{
int tmp = *a;
*a = *b;
*b = tmp;
}
void quickSort(int arr[], int low, int high)
{
int pvt = arr[high];
int i = low;
int j = high;
while (i < j)
{
while (pvt > arr[i])
i++;
while (pvt <= arr[j])
j--;
if (i < j)
swap(&arr[i], &arr[j]);
}
swap(&arr[i], &pvt);
printArr(arr, high + 1);
}
void main()
{
int arr[] = {10, 16, 8, 12, 15, 6, 3, 9, 5};
int n = sizeof(arr) / sizeof(arr[0]);
quickSort(arr, 0, n - 1);
}
Just after 2-3 minutes, a friend of mine helped me out, that the pivot is not present in the array so with what I'm swapping it with arr[i]? Instead I can swap 2 values for the same result, arr[i] and arr[high]. Got my mistake :P

Hoare partition correctness

according to introduction to algorithms I wrote a code for quicksort using Hoare's partition in the codeblocks IDE .The code was successfully built but the sorted array is not displayed on the console,only the unsorted array is displayed followed by a blinking underscore.
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
int partition(int arr[],int p,int r)
{
int i,j,x,temp;
x=arr[p];
i=p-1;
j=r+1;
while(true)
{
do{
j=j-1;
}while(arr[j]<=x);
do{
i=i+1;
}while(arr[i]>=x);
if (i<j)
{
temp=arr[i];
arr[i]=arr[j];
arr[j]=temp;
}
else
return j;
}
}
void quicksort(int arr[],int p,int r)
{
if (p<r)
{
int q=partition(arr,p,r);
quicksort(arr,p,q-1);
quicksort(arr,q-1,r);
}
}
void print(int A[],int size)
{
int i;
for(i=0;i<size;i++)
printf("%d ",A[i]);
}
int main()
{
int arr[]={1,12,56,2,67,0,98,23};
int size=sizeof(arr)/sizeof(arr[0]);
printf("\nthe array is\n");
print(arr,size);
quicksort(arr,0,size-1);
printf("\nthe sorted array is\n ");
print(arr,size);
return 0;
}
the output was as follows
the array is
1 12 56 2 67 0 98 23
`
Okay, I refactored your algorithm, based on a guide from wikipedia: https://en.wikipedia.org/wiki/Quicksort
As mentioned in my comment above, the [recursive] quicksort calls used the wrong arguments. But, then, as Weather Vane mentioned, it [still] didn't sort.
Edit: My original post was using Lomuto partitioning instead of Hoare.
The partition algorithm differed from the wiki by using a different initial value for the pivot and using <=,>= on the do/while termination conditions instead of <,>
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
int
partition(int arr[], int p, int r)
{
int i,
j,
x,
temp;
x = arr[(p + r) / 2];
i = p - 1;
j = r + 1;
while (1) {
do {
i += 1;
} while (arr[i] < x);
do {
j -= 1;
} while (arr[j] > x);
if (i >= j)
return j;
temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
void
quicksort(int arr[], int p, int r)
{
if (p < r) {
int q = partition(arr, p, r);
quicksort(arr, p, q);
quicksort(arr, q + 1, r);
}
}
void
print(int A[], int size)
{
int i;
for (i = 0; i < size; i++)
printf("%d ", A[i]);
}
int
main()
{
int arr[] = { 1, 12, 56, 2, 67, 0, 98, 23 };
int size = sizeof(arr) / sizeof(arr[0]);
printf("\nthe array is\n");
print(arr, size);
quicksort(arr, 0, size - 1);
printf("\nthe sorted array is\n ");
print(arr, size);
printf("\n");
return 0;
}

Quick sort recursive function in C - doesn't work with big number of elements

Has this function been written correctly?
It seems that something is wrong when I try to run the function with a large number of elements in the array (eg 1000).
Then its appears to stop.
int quick_sort(int n, int tablica[],int b, int a)
{
if(a==n-1 || n==0) return;
if(b==n-1)
{
b=0;
a++;
}
if(tablica[b]>tablica[b+1])
{
bufor=tablica[b];
tablica[b]=tablica[b+1];
tablica[b+1]=bufor;
}
b++;
return quick_sort(n,tablica,b,a);
}
Above code will not work even for a small array, unless the small array is unsorted in a particular way. It compares one element with the next element. If the array is say {4,3,8,7,1} the sort will fail, because it has no mechanism to push 1 to the start of the array.
For larger arrays there are too many recursion and the program hits the stack limit and simply fails.
You can use recursion in quicksort but the number of recursions has to be kept in check. For example for array of size 1000 you don't want to have to more than 1000 recursion. Example:
void swap(int* a, int* b)
{
int t = *a;
*a = *b;
*b = t;
}
void quicksort(int arr[], int low, int high)
{
if(low < high)
{
int pivot = arr[high];
int i = (low - 1);
for(int j = low; j <= high - 1; j++)
{
if(arr[j] <= pivot)
{
i++;
swap(&arr[i], &arr[j]);
}
}
swap(&arr[i + 1], &arr[high]);
int pi = i + 1;
quicksort(arr, low, pi - 1);
quicksort(arr, pi + 1, high);
}
}
int main()
{
int arr[] = { 7,3,6,1,4,8,9,2 };
int arrsize = sizeof(arr) / sizeof(*arr);
quicksort(arr, 0, arrsize - 1);
for(int i = 0; i < arrsize; i++)
printf("%d\n", arr[i]);
return 0;
}

Why changing random number generator changes running time of quick sort in C

I'm written a quick sort implementation in C. Changing the rand function range(using the remainder) in the first loop changes the running time of the algorithm dramatically. As it is right now, the algorithm takes 43 seconds. Changing the range from 100 to 10000 reduces the running to 0.9 seconds.
Why is that?
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
void quick_sort(int array[], int low, int high);
int partition(int array[], int low, int high);
void swap(int *a, int *b)
{
int temp = *a;
*a = *b;
*b = temp;
}
int main(void)
{
const int len = 1000000;
srand(time(NULL));
int array[len];
puts("Populating the array...\n");
for(int i = 0; i < len; i++)
array[i] = rand() % 100; // Changing this line dramatically reduce the running time
puts("|Now sorting the array...|\n");
quick_sort(array, 0, len-1);
/*for(int i = 0; i < len; i++)*/
/*printf("%d ", array[i]);*/
}
void quick_sort(int array[], int low, int high)
{
int j;
if(low < high)
{
j = partition(array, low, high);
quick_sort(array, low, j-1);
quick_sort(array, j+1, high);
}
}
int partition(int array[], int low, int high)
{
int pivot = array[high];
int leftwall = low-1;
for(int i = low; i < high; i++)
{
if(array[i] <= pivot)
{
++leftwall;
swap(&array[leftwall], &array[i]);
}
}
swap(&array[leftwall+1], &array[high]);
return ++leftwall;
}
My guess is that when partitioning the array you end up moving a large number of duplicate values. When you pick the random numbers from only 100 choices, the array of a million elements will have about 10,000 of each value. It looks like you'll be swapping them around every call to partition due to the array[i] <= pivot comparison. For example, when you are almost done and a partition has only two distinct values in it, it still has about 20,000 elements…

Segmentation error but I don't know why

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define MAX_SIZE 100
I am trying to quicksort an array of 2D points based upon their distance from the origin but my code hits a Seg fault after the first scanf.
typedef struct point{
double x;
double y;
double dist;
} point;
void sortpoints(point arr[], int low, int high);
void printpoints(point arr[], int n);
Sortpoints is just a manipulation of a quicksort in ordering an array of Point structs depending on the value of Point.dist
void sortpoints(point arr[], int low, int high){
int piv, i, j;
piv = low;
i = low;
j = high;
point box;
if(low < high){
while(i<j){
while((arr[i].dist)<=(arr[piv].dist) && i<= high)
i++;
}
while((arr[j].dist) > (arr[piv].dist) && j>= low)
j--;
}
if(i<j){
box = arr[i];
arr[i] = arr[j];
arr[j] = box;
}
box = arr[j];
arr[j] = arr[piv];
arr[piv] = box;
sortpoints(arr, low, j-1);
sortpoints(arr, j+1, high);
}
Printpoints just prints the points in order of their distances from the origin
void printpoints(point arr[], int n){
int i; for(i = 0; i <= n; i++){
printf("(%.2lf, %.2lf)\n", arr[i].x, arr[i].y);
}
}
The user enters the number of points and value of the points in the form (point.x, point.y)
int main(){
point pointa;
point pointarray[MAX_SIZE];
int n=0;
printf("how many points would you like to enter?\n");
scanf("%d", &n);
if(n<MAX_SIZE){
int i;
for(i=0; i<n ; i++){
scanf("(%lf,%lf)", &pointa.x, &pointa.y);
pointa.dist = sqrt(pointa.x*pointa.x + pointa.y*pointa.y);
pointarray[i] = pointa;
}
sortpoints(pointarray, 0, n-1);
printpoints(pointarray, n);}
else{
printf("sorry, not a valid array size\n");
}
return 0;
}
I've got stack overflow.
Your program calls function sortpoints, and calls itself too (sortpoints calls sortpoints). But i cant see where sortpoints must stop!
As a result, j-1 goes under null, and arr[j] is not valid at all.
When I changed this line:
scanf("(%lf,%lf)", &pointa.x, &pointa.y);
To this:
scanf("%lf,%lf", &pointa.x, &pointa.y);
The point values were actually being read in, with the parens there nothing gets read in, I don't see anything in the documentation on scanf about this though, is anyone familiar with this?
You sorting code seems to go into infinite recursion and cause a stack overflow however.
Your issue is with your braces. I have reformatted your sortpoints function slightly so it is clearer where each basic block actually is.
void sortpoints(point arr[], int low, int high){
int piv, i, j;
piv = low;
i = low;
j = high;
point box;
if(low < high){
while(i<j){
while((arr[i].dist)<=(arr[piv].dist) && i<= high)
i++;
}
while((arr[j].dist) > (arr[piv].dist) && j>= low)
j--;
}
if(i<j){
box = arr[i];
arr[i] = arr[j];
arr[j] = box;
}
box = arr[j];
arr[j] = arr[piv];
arr[piv] = box;
sortpoints(arr, low, j-1);
sortpoints(arr, j+1, high);
}
It should be evident now that your segfault is the result of accidental infinite recursion. This is a good argument for using { } for your loops, even with a single statement.

Resources