Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Quicksort: pivot position after one partition

I am reading about quicksort, looking at different implementations and I am trying to wrap my head around something.

In this implementation (which of course works), the pivot is chosen as the middle element and then the left and right pointer move to the right and left accordingly, swapping elements to partition around the pivot.

I was trying the array [4, 3, 2, 6, 8, 1, 0].

On the first partition, pivot is 6 and all the left elements are already smaller than 6, so the left pointer will stop at the pivot. On the right side, we will swap 0 with 6, and then 1 and 8, so at the end of the first iteration, the array will look like:

[4, 3, 2, 0, 1, 8, 6].

However, I was under the impression that after each iteration in quicksort, the pivot ends up in its rightful place, so here it should end up in position 5 of the array.

So, it is possible (and ok) that the pivot doesn't end up in its correct iteration or is it something obvious I am missing?

like image 558
kenny Avatar asked Jan 21 '15 13:01

kenny


People also ask

How do you choose a pivot point for quick sort?

You should choose the pivot randomly. Another way is to choose the median value from the first, the last, and the middle element of the array. Say we have 8 1 6 9 6 3 5 2 7 0 And 6 is chosen as the pivot.

How the pivot is selected and partition is done in quick sort?

The key process in quickSort is a partition(). The target of partitions is, given an array and an element x of an array as the pivot, put x at its correct position in a sorted array and put all smaller elements (smaller than x) before x, and put all greater elements (greater than x) after x.

Does quicksort follows divide-and-conquer?

Like merge sort, quicksort uses divide-and-conquer, and so it's a recursive algorithm.

Is dual pivot quicksort better?

Dual pivot quick sort is a little bit faster than the original single pivot quicksort. But still, the worst case will remain O(n^2) when the array is already sorted in an increasing or decreasing order.


1 Answers

There are many possible variations of the quicksort algorithm. In this one it is OK for the pivot to be not in its correct place in its iteration.

The defining feature of every variation of the quicksort algorithm is that after the partition step, we have a part in the beginning of the array, where all the elements are less or equal to pivot, and a non-overlapping part in the end of the array where all the elements are greater or equal to pivot. There may also be a part between them, where every element is equal to pivot. This layout ensures, that after we sort the left part and the right part with recursive calls, and leave the middle part intact, the whole array will be sorted.

Notice, that in general elements equal to pivot may go to any part of the array. A good implementation of quicksort, that avoids quadratic time for the most obvious case, i.e. all equal elements, must spread elements equal to pivot between parts rationally.

Possible variants include:

  • The middle part includes only 1 element: the pivot. In that case pivot takes its final place in the array after the partition and won't be used in the recursive calls. That's what you meant by pivot taking its place in its iteration. For this approach the good implementation must move about half the elements equal to pivot to the left part and the other half to the right part, otherwise we would have quadratic time for an array with all equal elements.
  • There is no middle part. Pivot and all elements equal to it are spread between the left and the right part. That's what the implementation you linked does. Once again, in this approach about half of the elements equal to pivot should go to the left part, and the other half to the right part. This can also be mixed with the first variation, depending on whether we are sorting an array with an odd or an even number of elements.
  • Every element equal to pivot goes to the middle part. There are no elements equal to pivot in either left or right part. That's quite efficient and that's the example Wikipedia gives for solving the all-elements-equal problem. Arrays with all elements equal to each other are sorted in linear time in that case.

Thus, the correct and efficient implementation of quicksort is quite tricky (there is also a problem of choosing a good pivot, for which several approaches with different tradeoffs exist as well; or an optimisation of switching to another non-recursive sorting algorithm for smaller sub-array sizes).

Also, it seems that the implementation you linked to, may do recursive calls on overlapping subarrays:

if (i <= j) {
  exchange(i, j);
  i++;
  j--;
}

For example, when i is equal to j, those elements will be swapped, and i will become greater than j by 2. After that 3 elements will overlap between the ranges of the following recursive calls. The code still seems to work correctly though.

like image 68
Kolmar Avatar answered Oct 19 '22 08:10

Kolmar