1

Consider the following algorithm:

void qsort(int arr[], int left, int right) {
        if (left < right) {
        int index = partition(arr, left, right);
        qsort(arr, left, index - 1);
        qsort(arr, index + 1, right);
    }
}

int partition(int arr[], int left, int right) {
    int pivot = arr[right];
    int i = left - 1;
    for (int j = left; j < right; j++) {
        if (arr[j] <= pivot) {
            ++i;
            swap(&arr[i], &arr[j]);
        }
    }
    swap(&arr[i + 1], &arr[right]);
    return i + 1;
}

inline void swap(int* i, int* j) {
    int temp = *i;
    *i = *j;
    *j = temp;
}

After I fixed the segfaults, I noticed that the algorithm always produces a garbage value at arr[0]. So if the input array is: 5 5 1 3 7 0 0 0 3 , the output is -858993460 0 0 0 1 3 3 5 5. I've ran this through a debugger numerous times and nevertheless I still have no idea where the garbage value comes from. What's more interesting is that in Java pretty much the same algorithm works perfectly.

edit The initial function is called like this: qsort(arr, 0, 9); where 9 is the length of the array - 1.

  • 1
    *"pretty much the same"* != *exactly the same* – CinCout May 10 '19 at 05:37
  • 1
    How are you calling your `qsort()`, i.e. what are the exact values of `left` and `right` for the array in your question (`5 5 1 3 7 0 0 0 3`)? – NPE May 10 '19 at 05:38
  • 2
    Notice that your garbage result has also lost the `7` — the biggest value. You're accessing the array out of bounds. So, a lot hinges on how you invoke the function. – Jonathan Leffler May 10 '19 at 05:40
  • The function signatures are different and `swap` takes a reference to the array alongside with 2 indexes. That's it. Outside of that the logic is *exactly the same*. – Mark Ceitlin May 10 '19 at 05:41
  • 1
    With quicksort, you must specify whether the original range passed is *"inclusive"* or *"exclusive"*. For example, you pass 9-elements, are you passing original indexes with `left` as `0` and `right` as `8` (or `9`)? – David C. Rankin May 10 '19 at 05:43

2 Answers2

4

I suspect you have an off-by-one error in how you initialize arr or how you call qsort(). Likely it gets called with a garbage (uninitialized) element either at the start or at the end of the array. This also likely explains why the largest value, 7, is missing from the output.

If I were to speculate further, I'd guess that in Java, the array gets initialized with zeros and so you get an extra zero in the output (that perhaps you're overlooking amongst the other zeros?)

edit: The initial function is called like this: qsort(arr, 0, 9); where 9 is the length of the array - 1.

The 9 is clearly not correct for your example, so here is one error. It would account for the garbage element but not for the missing element.

My next hypothesis is that, having sorted a ten-element array (9 real + 1 garbage) you then only print out the first nine elements. This would account for the missing 7 in your output (it's the largest and so gets placed in the final spot, which is the spot that doesn't get printed out).

P.S. If I may offer some unsolicited advice for future questions, posting a Minimal, Complete, and Verifiable example would make all this debugging-by-conjecture completely unnecessary as we'd be able to see right away what exactly is going on with your code. :)

NPE
  • 486,780
  • 108
  • 951
  • 1,012
  • `arr[0] = 3 arr[1] = 0 arr[2] = 8 arr[3] = 8 arr[4] = 7 arr[5] = 9 arr[6] = 7 arr[7] = 9 arr[8] = 1 arr[9] = 7` with the output array being: `0 1 3 7 7 8 8 9 9 7`. I changed the initial function call to `right` being the size of the array - 2. No garbage value this time, but the last number is not in its correct space. – Mark Ceitlin May 10 '19 at 05:57
2

If you invoke the function with the size instead of the index of the right-most element (which is the size - 1), you access the array out of bounds.

This code works:

#include <stdio.h>

static
inline void swap(int *i, int *j)
{
    int temp = *i;
    *i = *j;
    *j = temp;
}

static
int partition(int arr[], int left, int right)
{
    int pivot = arr[right];
    int i = left - 1;
    for (int j = left; j < right; j++)
    {
        if (arr[j] <= pivot)
        {
            ++i;
            swap(&arr[i], &arr[j]);
        }
    }
    swap(&arr[i + 1], &arr[right]);
    return i + 1;
}

static
void qsort(int arr[], int left, int right)
{
    if (left < right)
    {
        int index = partition(arr, left, right);
        qsort(arr, left, index - 1);
        qsort(arr, index + 1, right);
    }
}

static void dump_array(const char *tag, int size, int *arr)
{
    printf("%s (%d):", tag, size);
    for (int i = 0; i < size; i++)
        printf(" %d", arr[i]);
    putchar('\n');
}

int main(void)
{
    int arr[] = { 5, 5, 1, 3, 7, 0, 0, 0, 3, };
    enum { ARR_SIZE = sizeof(arr) / sizeof(arr[0]) };

    dump_array("Before", ARR_SIZE, arr);
    qsort(arr, 0, ARR_SIZE - 1);
    dump_array("After", ARR_SIZE, arr);
    return 0;
}

Output:

Before (9): 5 5 1 3 7 0 0 0 3
After (9): 0 0 0 1 3 3 5 5 7
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278