-1

The functions below are an implementation of Quick sort. Here we take the last element as a pivot.

I understood the partition function(where the pivot comes to its sorted position) but I can't understand the recursive function qs. The function qs calls itself recursively to solve the left side by qs(a,start,pi-1) and the right of the partition by qs(a,pi+1,end).

Does it the solve the left and then the (left of the left) then (the left of(the left of the left), etc, and then left, left...right, etc. Or does it alternate by solving the left side and then right side.

PS: I want to know whats happening inside the computer, the mechanism of this recursion of quick sort. The program is working but I want to know how it works.

int partition(int *a, int start, int end)
{   
    int pivot=a[end];
    int pi=start;
    for(int i=start; i<end; i++)
    {
        if(a[i]<=pivot)
        {
            swap(a[i],a[pi]);
            pi++;
        }
    }
    swap(a[pi], a[end]);
    return pi;
}

void qs(int*a, int start, int end)
{
    if(start<end)
    {
        int pi=partition(a,start,end);
        qs(a,start,pi-1);
        qs(a,pi+1,end);
    }
}
Fede
  • 3,928
  • 1
  • 20
  • 28
neOh
  • 1
  • 1
    The first one (left, left, left, left, ... right). The first recursive call to `qs` is on the left partition of the array. The recursive call to the right partition of the array will not be made until the first call returns, i.e. until the left partition is completely sorted. Another way to look at this is that you're performing a depth-first traversal of the recursion tree. – beaker Dec 13 '15 at 15:47
  • @beaker After the first partition, the left is partitioned again & again to the left but what about the right side of the left side's partition(the 2nd partition on the left, its right side)? – neOh Dec 13 '15 at 15:59
  • @beaker Also, after the left side(1st partition) is sorted, then when it is sorting the right side qs(a,pi+1,end), won't the left side function qs(a,start,pi-1) also be called? So won't the right side(1st partition) be sorted by a different process than the left side? – neOh Dec 13 '15 at 16:07
  • 1
    you should read up on subroutines i.e. function calls and the resulting [call stack structure](https://en.wikipedia.org/wiki/Call_stack#Structure) – BeyelerStudios Dec 13 '15 at 16:09

2 Answers2

3

Example of the order of operations for Lomuto partition scheme, where pivot = array[high].

quicksort(array, low, pivot-1), quicksort(array, pivot+1, high).

A vertical bar used to show left sub-array, pivot, right sub-array.

  11 13 14 12 10  8  9  5  6  4  2  0  1  3  7
   5  6  4  2  0  1  3 11 13 14 12 10  8  9  7 
   5  6  4  2  0  1  3| 7|13 14 12 10  8  9 11
   2  0  1  5  6  4  3 
   2  0  1| 3| 6  4  5
   0  2  1 
   0| 1| 2
               4  6  5
               4| 5| 6
                          10  8  9 13 14 12 11
                          10  8  9|11|14 12 13
                           8 10  9
                           8| 9|10
                                      12 14 13
                                      12|13|14
   0  1  2  3  4  5  6  7  8  9 10 11 12 13 14
rcgldr
  • 27,407
  • 3
  • 36
  • 61
  • 1
    Great! Just as side note: In your sample the partitions (left side and right side) always have the same size. That it is not necessarily the case. For example, if you have `8 4 7 6 5 9 2 1 3` , then pivot is `3`, and the left partition has 2 elements, the right 6 elements – SQL Police Dec 14 '15 at 08:36
  • 1
    @SQLOTL - I was trying to make a "pretty" example, mostly to show depth first / left first concept. – rcgldr Dec 14 '15 at 09:38
  • Yes this is the **Best Case**. Then you have O (n*log(n)). But reality is different ;) BTW, the **Worst Case** is that the original list is sorted in reverse. Then Quick Sort becomes O(n^2). In fact, reality is somewhere between best and worst case. – SQL Police Dec 14 '15 at 10:15
  • @SQLOTL - if [Hoare partition scheme](http://en.wikipedia.org/wiki/Quicksort#Hoare_partition_scheme), with pivot = array[(low+high)/2] is used, then it's fastest with sorted or reverse sorted data. There are still worst case data patterns, but at least the simple cases are handled. – rcgldr Dec 14 '15 at 13:03
1

The best way for understanding the order in which things are happening that I can suggest you, is by printing some debugging info in your qs method. To achieve that, I would add an additional argument by ref, in which I would count the number of times the qs function is called, and print that info next to the bounds of the partition being solved. e.g.

void qs(int*a, int start, int end, int &stepCount)
{
    if(start<end)
    {
        int currentStep = stepCount++;
        cout << "Solving step " << currentStep << " partition from " << start << " to " << end << endl;
        int pi=partition(a,start,end);
        qs(a,start,pi-1,stepCount);
        qs(a,pi+1,end,stepCount);
        cout << "Finished solving step " << currentStep << endl;
    }
}

Don't understand your PS question. It's very broad. You mean specifically in the partitioning? In how recursion is handled? How the bits move around in memory?

Fede
  • 3,928
  • 1
  • 20
  • 28