Segmentation in QuickSort - c

I'm getting a segmentation fault:11 when I try to run this QuickSort, but it compiles fine. I'm running it with a driver, which is why I use quicksort() and quicksortR(). What's causing the segmentation?
/* -------- Quick sort stuff starts here --------- */
int partition(int array[], int start, int stop) {
int compars = 0;
int pivot = array[stop];
int i = start - 1;
for (int j = start; j <= stop - 1; j++) {
if (array[j] <= pivot) {
i++;
int temp = array[j];//swaps values of i and j
array[j] = array[i];
array[i] = temp;
}
compars++;
}
int temp = array[i + 1];
array[i + 1] = array[stop];
array[stop] = temp;
return compars;
}
int quickSortR(int array[], int start, int stop) {
int compars = 0;
int mid = array[stop];
if (start < stop) {
compars = compars + partition(array, start, stop);
quickSortR(array, start, mid - 1);
quickSortR(array, mid+1, stop);
}
return compars;
}
int quickSort(int array[], int n) {
return quickSortR(array, 0, n);
}
/* ----------- end quick sort stuff ----------------- */

You call quicksort with the number of elements of the array as the stop argument, but you initialize the pivot as int pivot = array[stop];. You are reading past the end of the array. Undefined behavior.
There are probably other problems in the code, but this alone explains the crash.

I'm getting a segmentation fault:11 when I try to run this QuickSort, but it compiles fine
Please note: program compiling means compiler understands what you want your program to do. In no way compiler checks if what your program does makes any sense whatsoever.
If it knew what you want to do why wouldn't it write the program itself?

Related

My quicksort algorithm is giving me a trace trap, how can I fix it?

So currently I am trying to make a quicksort algorithm for an array of strings (to sort them alphabetically) since I can't use the qsort() function for this exercise and I also cannot allocate memory (malloc(), etc). So, I tried to do it recursively. After testing the first time it worked but as I added more text to the array, it now throws a trace trap which I don't know how to fix.
#include <stdio.h>
#include <string.h>
void swap(char a[], char b[])
{
char temp[51];
strcpy(temp, a);
strcpy(a, b);
strcpy(b, temp);
}
void quicksort(char array[10000][51], int start, int end)
{
int i, j, pivot;
if( start < end )
{
pivot = start;
i = start;
j = end;
while( i < j)
{
/* i & pivot */
while( (strcmp(array[i], array[pivot]) <= 0) && i < end )
i++;
/* j & pivot */
while( (strcmp(array[j], array[pivot]) > 0) )
j--;
if( i < j )
{
swap(array[i], array[j]);
}
}
swap(array[pivot], array[j]);
quicksort(array, start, j - 1);
quicksort(array, j + 1, end);
}
}
The way I call it is pretty simple:
int main()
{
int i;
char input[10000][51] = {"this is a test", "another", "fffff", "a" , "skjfkdjf"};
quicksort(input, 0, 4);
/* used to print the strings */
for(i = 0; i < 5; i++)
{
printf("%s\n", input[i]);
}
}
However this throws a trace trap.
If someone could help me find out what is wrong and fix it that would be great!!
Thank you.
The problem is that you're swapping the value with itself here:
swap(array[pivot], array[j]);
I believe:
i = start + 1;
would be a slight optimization, and together with
if (pivot != j) {
swap(array[pivot], array[j]);
}
would be sufficient fix.

My function for generating random numbers isn't going past 500000

I'll get right into my problem. So basically what I want to do is to generate an array of random numbers of different amounts. So one with 10,000, 50,000, 100,000, 500,000, 600,000, etc. Then I would sort them using quicksort and print the sorted array to the screen. Additionally, the time taken for it to run would be recorded and printed as well. The only part I'm having problems with however is generating the array. For some reason generating past 500,000 random numbers does not work and returns this:
Process exited after 2.112 seconds with return value 3221225725
Press any key to continue . . .
([1]: https://i.stack.imgur.com/m83el.png)
This is my code:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
void randNums(int array[], int range) {
int i, num;
for (i = 0; i < range; i++) {
num = rand() % range;
array[i] = num;
}
}
//prints elements of given array
void display(int array[], int size) {
int i;
for (i = 0; i < size; i++) {
printf("#%d. %d\n", i, array[i]);
}
}
//displays time taken for sorting algorithm to run
void timeTaken(char sortingAlgo[], int size, clock_t start, clock_t end) {
double seconds = end - start;
double milliseconds = seconds / 1000;
printf("Time taken for %s Sort to sort %d numbers was %f milliseconds or %f seconds",
sortingAlgo, size, milliseconds, seconds);
}
//quick sort
void quickSort(int array[], int first, int last) {
int i, j, pivot, temp;
if (first < last) {
pivot = first;
i = first;
j = last;
while (i < j) {
while (array[i] <= array[pivot] && i < last)
i++;
while (array[j] > array[pivot])
j--;
if (i < j) {
temp = array[i];
array[i] = array[j];
array[j] = temp;
}
}
temp = array[pivot];
array[pivot] = array[j];
array[j] = temp;
quickSort(array, first, j - 1);
quickSort(array, j + 1, last);
}
}
int main() {
int size = 600000;
int myArray[size];
time_t end, start;
int first, last;
randNums(myArray, size);
first = myArray[0];
last = sizeof(myArray) / sizeof(myArray[0]);
time(&start);
quickSort(myArray, first, last);
time(&end);
display(myArray, size);
timeTaken("Quick", size, start, end);
return 0;
}
Any help would be greatly appreciated, Thank you!
There's a lot of little bugs in this code that aren't too difficult to resolve. I'll try and break it down here in this refactoring and cleanup:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
void randNums(int* array, int range) {
// Declare iterator variables like `i` within the scope of the iterator.
for (int i = 0; i < range; i++) {
// No need for a single-use variable here, just assign directly.
array[i] = rand () % range;
}
}
void display(int* array, int size) {
// for is not a function, it's a control flow mechanism, so
// it is expressed as `for (...)` with a space. `for()` implies
// it is a function, which it isn't.
for (int i = 0; i < size; i++) {
printf("#%d. %d\n", i, array[i]);
}
}
void timeTaken(char* sortingAlgo, int size, clock_t start, clock_t end) {
// Time calculation here needs to account for the fact that clock_t
// does not use seconds as units, it must be converted
// https://en.cppreference.com/w/c/chrono/clock_t
printf(
"Time taken for %s Sort to sort %d numbers was %.6f seconds",
sortingAlgo,
size,
((double) (end - start)) / CLOCKS_PER_SEC
);
}
void quickSort(int* array, int first, int last) {
// Establish a guard condition. Rest of the function is no longer
// nested in a control flow structure, so it simplifies the code.
if (first >= last) {
return;
}
int pivot = first;
int i = first;
int j = last;
// Use `while (...)` as it's also a control flow structure.
while (i < j) {
// Adding space around operators improves clarity considerably. Unspaced
// elements like `a->b()` are supposed to stand out and not be confused
// with visually similar `a>>b()` which does something very different.
while (array[i] <= array[pivot] && i < last) {
i++;
}
// Use surrounding braces on all blocks, even single-line ones, as this
// can avoid a whole class of errors caused by flawed assumptions.
// while (...) { ... }
while (array[j] > array[pivot]) {
j--;
}
if (i < j) {
int temp = array[i];
array[i] = array[j];
array[j] = temp;
}
}
int temp = array[pivot];
array[pivot] = array[j];
array[j] = temp;
quickSort(array, first, j - 1);
quickSort(array, j + 1, last);
}
int main(int argc, char** argv) {
int size = 600000;
// If an argument was given...
if (argc > 1) {
// ...use that as the size parameter instead.
size = atol(argv[1]);
}
// Allocate an array of sufficient size
int* numbers = calloc(size, sizeof(int));
randNums(numbers, size);
// time_t has at best second-level precision, it's very inaccurate.
// Use clock_t which gives far more fidelity.
clock_t start = clock();
// This function takes *offsets*, not values.
quickSort(numbers, 0, size - 1);
clock_t end = clock();
display(numbers, size);
timeTaken("Quick", size, start, end);
free(numbers);
return 0;
}
The number one bug here was calling quickSort() incorrectly:
// Represents first *value* in the array
first = myArray[0]; // Should be: 0
// Rough calculation of the size of the array, but this is off by one
last = sizeof(myArray)/sizeof(myArray[0]); // Should be: size - 1
quickSort(myArray, first, last);

C quick sort function keeps crashing

Part of an assignment I'm doing for school involved building a quick sort to sort an array. I'm pretty sure I have it close, however whenever I call it, it crashes on me
void quickSort(double * array, unsigned int size, int start, int stop)
{
int swapIndex = start;
int pivot = start;
double temp;
if (size > 1)
{
for (int i = pivot + 1; i < stop; ++i)
{
if (array[pivot] > array[i])
{
++swapIndex;
temp = array[i];
array[i] = array[swapIndex];
array[swapIndex] = temp;
}
}
temp = array[swapIndex];
array[swapIndex] = array[pivot];
array[pivot] = temp;
quickSort(array, size, start, swapIndex);
quickSort(array, size, swapIndex, size);
}
}
http://pastebin.com/Ccv4KP3j
N.B. This answer's based off the pastebin link as of 27/2/2016
First of all your function has the wrong return type - quicksort works in-place, meaning that it doesn't create any new arrays; it sorts the array you passed to it. It will work perfectly as a void function.
Remember that in C, arrays can only be passed by reference, i.e. every recursive call to quicksort deals with exactly the same array.
Your quicksort should work like so:
double arr[] = {12, -2, 4, 5, 2, 1};
quicksort(arr, 0, 5);
// arr is now sorted
int i;
for (i=0; i<6; i++){
printf("%f, ", arr[i]);
}
printf("\n");
// prints "-2, 1, 2, 4, 5, 12"
For the sake of clarity, I'd recommend writing a function void doubleSwap(double *a, double* b) to take care of all the element swapping without muddying your code.
The reason your code results in stack overflows is twofold:
The initial if guard needs to check if start and stop differ by
more than one, not just if they're different.
The 'swapIndex' variable always overlaps the pivot cell, resulting in
confusion as the pivot value gets mutated before the
whole array is processed. It can be fixed by setting pivot to
stop - 1.
Here is a pastebin of my version of your code, but before looking at it, try to debug it yourself using a bunch of printfs.
Also note that you don't have to pass the whole array to qsort - you can replace quickSort(array, swapIndex, stop) with quickSort(array + swapIndex, 0, stop - swapIndex), allowing you to get rid of start altogether because it's always zero.
void doubleSwap(double *a, double*b){
double temp = *a;
*a = *b;
*b = temp;
}
void quickSort(double * array, int start, int stop)
{
int pivot = stop - 1;
int swapIndex = start;
int i;
if (start < stop - 1) {
for (i = start; i < stop; i++) {
if (array[i] < array[pivot]){
doubleSwap(array + swapIndex, array + i);
swapIndex++;
}
}
// Note that `array + swapIndex` is equivalent to `&(array[swapIndex])`
doubleSwap(array + swapIndex, array + pivot);
fprintf(stderr, "swapIndex = %d start = %d stop = %d\n", swapIndex, start, stop);
for (i = 0; i< NELEMS; i++){
fprintf(stderr, "%3f, ", array[i]);
}
fprintf(stderr, "\n");
quickSort(array, start, swapIndex);
quickSort(array, swapIndex, stop);
}
}

Quicksort crashes with more than 500k elements

I have a problem in my pretty easy algorithm - quicksort in C.
It is very efficient (about 0.1s with randomize and checking if the list is sorted) but when i want to sort more than 500k elements it crashes.
Unfortunatelly i need to sort more of them because i need to write some kind of summary at the end :(
Here is my code, maybe someone will see a stupid mistake.
Thanks in advance!
int quick (int a[],int begin,int end)
{
int i = begin, j = end, w, q, pivot, k;
q=begin+end;
q=q/2;
pivot=a[q];
while (1)
{
while (a[j] > pivot && j>=0)
j=j-1;
while (a[i] < pivot && i<j)
i=i+1;
if (i < j)
{
k = a[i];
a[i] = a[j];
a[j] = k;
i++;
j--;
}
else
return j;
}
}
void quicks (int a[], int begin, int end)
{
int x;
if (end>begin)
{
x=quick(a,begin,end);
quicks(a,begin,x);
quicks(a,x+1,end);
}
}
It seems that i just need to use malloc and it is working fine. Thanks a lot for Your help!
You are suffering from RAM exhaustion/rollover: As you use an array of int, each of them requires 4 bytes. Your memory mapping is handled using size_t-type indexes. If you are compiling in 32-bit mode (which is probably your case), the maximum number it can get at is 2147483648 (2^31). With 4 bytes per int, you can only handle 536870912 elements (2^31 / 4).
As the system requires some RAM for other purposes (e.g. globals), you can only use a bit more than 500K entries.
Solution: Use a 64-bit compiler and you should be fine.
BR
Here is another and simpler implementation.
void quickSort(int a[], int begin, int end)
{
int left = begin - 1, right = end + 1, tmp;
const int pivot = a[(begin+end)/2];
if (begin >= end)
return;
while(1)
{
do right--; while(a[right] > pivot);
do left++; while(a[left] < pivot);
if(left < right)
{
tmp = a[left];
a[left] = a[right];
a[right] = tmp;
}
else
break;
}
quickSort(a, begin, right);
quickSort(a, right+1, end);
}
You call it like this
int main(void)
{
int tab[5] = {5, 3, 4, 1, 2};
int i;
quickSort(tab, 0, 4); // 4 is index of lest element of tab
for(i = 0; i < 5; i++)
printf("%d ", tab[i]);
printf("\n");
return 0;
}

Problem with my quicksort implementation

Newbie programmer here trying to implement quicksort, yet it won't work. I've looked at online resources but I just can't seem to spot the error in my implementation. Thanks in advance.
EDIT Issue I'm having seems like it gets stuck in the quicksort function, and the program just hangs. When I tried debugging it with printf's, the original array seems to have been modified with unexpected numbers (not from the original list), such as 0's.
void quicksort(int a[], const int start, const int end)
{
if( (end - start + 1 ) < 2)
return;
int pivot = a[rand()%(end - start)];
//Two pointers
int L = start;
int R = end;
while(L < R)
{
while(a[L] < pivot)
L++;
while(a[R] > pivot)
R--;
if(L < R)
swap(a,L,R);
}
quicksort(a, start, L-1);
quicksort(a, L+1, end );
}
void swap(int a[], const int pos1, const int pos2)
{
a[pos1] ^= a[pos2];
a[pos2] ^= a[pos1];
a[pos1] ^= a[pos2];
}
int main()
{
int array[20] = {0};
int size = sizeof(array)/sizeof(array[0]);//index range = size - 1
int i = 0;
printf("Original: ");
for (i; i < size; i++)
{
array[i] = rand()%100+ 1;
printf("%d ", array[i]);
}
printf("\n");
quicksort(array,0,size-1);
int j = 0;
printf("Sorted: ");
for(j; j < size; j++)
printf("%d ", array[j]);
printf("\n");
}
Additional Question: In regards to calling quicksort recursively, would the left and right pointer always point towards the pivot at the end of each partition? If so, is calling quicksort from start to L-1 and L+1 to end correct?
Also, is the if (L < R) before the swap necessary?
I believe that the problems stem from two errors in the logic. The first one is here:
int pivot = a[rand()%(end - start)];
Note that this always picks a pivot in the range [0, end - start) instead of [start, end). I think you want to have something like
int pivot = a[rand()%(end - start) + start];
so that you pick a pivot in the range you want.
The other error is in this looping code:
while(L < R)
{
while(a[L] < pivot)
L++;
while(a[R] > pivot)
R--;
if(L < R)
swap(a,L,R);
}
Suppose that L < R, but that a[L], a[R], and pivot are all the same value. This might come up, for example, if you were quicksorting a range containing duplicate elements. It also comes up when you use rand with the standard Linux implementation of rand (I tried this on my machine and 27 was duplicated twice). If this is the case, then you never move L or R, because the conditions in the loops always evaluate to false. You will need to update your logic for partitioning elements when duplicates are possible, since otherwise you'll go into an infinite loop here.
Hope this helps!
After the While statement, R should be less than L, try this:
quicksort(a, start, R);
quicksort(a, L, end );
And the statement if(L < R) is not necessary.

Resources