0

I code Quicksort using Hoare partitioning from the Cormen Algorithms book. I can't spot any mistakes in my code and it looks just like the pseudocode in the book.

swapping i, j : 0, 8
-2 2 -5 -3 6 0 1 0 -1 4

swapping i, j : 1, 3
-2 -3 -5 2 6 0 1 0 -1 4
p is: 2

swapping i, j : 0, 1
-3 -2 -5 2 6 0 1 0 -1 4
p is: 0

After it has done the above swaps, this code eventually ends up partitioning on a subarray {-3, -2}. For this subarray, pivot is -3 and the partition() returns 0 as the index (j). Since this subarray is already sorted with pivot -3 at 0th index position, no changes are done every time this is quicksorted. So the qsort loops forever.

Can someone tell me how this is different from the Hoare partition in the book and if same why is this not working?

void swap(int *a, int i, int j) {
        cout << "swapping i, j : " << i << ", " << j << endl;
        int tmp = a[i];
        a[i] = a[j];
        a[j] = tmp; }

int partition(int *a, int len) {
        int pivot = a[0];

        int i = -1, j = len;
        while (true) {
               while ( ++i && a[i] < pivot && i< j) {}
               while (--j && a[j] > pivot && i <j) {}
               if (i < j )
                  swap(a, i, j);
               else 
                  return j ;
        } }

void qsort(int a[], int len) {
        int p = partition(a, len);
        cout << "p is: " << p << endl;
        qsort(a, p);
        qsort(a+p, len - p ); }

int main(int argc, char *argv[]) {
        int a[10] = {-1, 2, -5, -3, 6, 0, 1, 0, -2, 4};
        qsort(a, 10); }
Joe Black
  • 625
  • 6
  • 19
  • When does `swapping i, j : 0, 1` happen? Did you mean `swapping i, j : 0, 2`? – CinCout Apr 26 '17 at 05:00
  • swapping i, j : 0, 1 means that values at index 0 and index 1 of the array 'a' input to swap are being swapped. – Joe Black Apr 26 '17 at 05:09
  • I got that, but I think indices `0` and `2` are being swapped instead, during the second call to `qsort(a, 3)` – CinCout Apr 26 '17 at 05:10
  • Added to the OP how the original array looks after every swap. After the third swap, the p is 0 and the subarray is {-3, -2} – Joe Black Apr 26 '17 at 05:21
  • After second swap, `p = 2`. Then in `partition(a, 3)`, `i` becomes `0` (as you rightly said), but `j` becomes `2` (and not `1`) because `-5 < -2` (`-2` is the `pivot`) – CinCout Apr 26 '17 at 05:26
  • Note that `partition()` returns 0-based index, but you need to pass length to `qsort()`, so it must be `qsort(a, p+1)` – CinCout Apr 26 '17 at 05:29
  • once p=2, partition(a, 2) is called, not partition (a, 3). At that point partition is trying to find 'p' for subarray {-2, -3}, and it does one more swap "swapping i, j : 0, 1" making it {-3, -2} and returns p=0. The output posted above is directly from running the program above. – Joe Black Apr 26 '17 at 05:31
  • That 0-based index point mentioned above could be the issue. I'll check that may be I need to call qsort(a, 3) at p = 2. – Joe Black Apr 26 '17 at 05:41

1 Answers1

1

Extending my comment in an answer, partition() returns 0-based index, but you need to pass the array length (length is 1-based) to qsort(), so it must be:

void qsort(int a[], int len)
{
    int p = partition(a, len);
    cout << "p is: " << p << endl;
    qsort(a, p + 1); // note p+1 instead of p
    qsort(a + p + 1, len - (p + 1)); // note p+1 instead of p
}

The dry run will look like:

swapping i, j : 0, 8
-2 2 -5 -3 6 0 1 0 -1 4

swapping i, j : 1, 3
-2 -3 -5 2 6 0 1 0 -1 4
p is: 2

Now you must call qsort(a, 3) since you want to sort the sub-array -2 -3 -5. Also, qsort(a+3, 7) for the sub-array 2 6 0 1 0 -1 4

CinCout
  • 9,486
  • 12
  • 49
  • 67
  • This seems right, the qsort(a, p+1) call needs to be made. So I understand that after partitioning subarray indices 0 to p are <= pivot, and subarray indices p+1 to len-1 are >= pivot. Can partition ever return at i ==j ? I guess it's interesting that Cormen book mentions that if we chose a[len -1] as the pivot instead, then this code will go in an infinite loop for an array in which a[len -1] is the largest element. There has to be a corresponding case for infinite loop when a[0] is the smallest element and a[0] is pivot (above code does this). What should partition return for that case? – Joe Black Apr 26 '17 at 06:56
  • I am afraid I don't understand the use case you stated above. – CinCout Apr 26 '17 at 08:15