Search code examples
algorithmsortingquicksort

Why is the pivot element moved to the first or last position of the array before partitioning in Quicksort?


I read in some places that if we dont choose the first or last element as the pivot, we should first swap it with the first or last position before the partitioning begins. So I tried an example and I am getting the correct partition using this algorithm https://www.cs.auckland.ac.nz/software/AlgAnim/qsort1a.html
This partitioning method uses a left pointer and a right pointer. It moves the left pointer towards the center till it finds an element greater than the pivot. Then it moves the right pointer towards the center till it finds an element less than the pivot. If rightpointer > leftpointer. The values at these two locations are swapped. Finally the pivot is placed at the location of the right pointer.
For the input array 12, 18, 17, 11, 13, 15, 16, 14 the element 15 is chosen as the pivot.
These are the steps:
12, 18, 17, 11, 13, 15, 16, 14

12, 14, 17, 11, 13, 15, 16, 18 (swap 18 and 14)

12, 14, 13, 11, 17, 15, 16, 18 (swap 17 and 13)

12, 14, 13, 11, 15, 17, 16, 18 (swap 15 and 17)


Solution

  • The Hoare partition scheme is similar in concept to the example in the question, except that the initial pivot value can be taken from any place within the array, and no special end case swapping is performed, as the pivot value and pivot pointer will end up in it's correct position during the Hoare partitioning.

    Here is an example of quicksort that uses median of 3, Hoare partition scheme, exclusion of elements adjacent to and equal to pivot (they are already sorted), and only using recursion on the smaller partition to limit worst case stack space to O(log(n)).

    void QuickSort(uint32_t a[], size_t lo, size_t hi) {
        while(lo < hi){
            size_t i = lo, j = (lo+hi)/2, k = hi;
            uint32_t p;
            if (a[k] < a[i])            // median of 3
                std::swap(a[k], a[i]);
            if (a[j] < a[i])
                std::swap(a[j], a[i]);
            if (a[k] < a[j])
                std::swap(a[k], a[j]);
            p = a[j];
            i--;                        // Hoare partition
            k++;
            while (1) {
                while (a[++i] < p);
                while (a[--k] > p);
                if (i >= k)
                    break;
                std::swap(a[i], a[k]);
            }
            i = k++;
            // at this point, a[i] or a[k] or both == p  (pivot value)
            while(i > lo && a[i] == p)  // exclude middle values == pivot
                i--;
            while(k < hi && a[k] == p)
                k++;
            // recurse on smaller part, loop on larger part
            if((i - lo) <= (hi - k)){
                QuickSort(a, lo, i);
                lo = k;
            } else {
                QuickSort(a, k, hi);
                hi = i;
            }
        }
    }