I have seen various tweaks for quicksort and to establish their usefulness, I designed a program that randomly generates arrays and times how long quicksort takes to sort them. Right now I'm focusing on how the pivot is chosen. I'm comparing choosing the first element as the pivot versus choosing the median of first, middle and last elements. I came across [an implementation][1]an implementation that presorts the first, middle and last element and have to implemented it for my tests.
- theThe index of the middle element is computed
- theThe 3 if statements rearange the first, middle and last element so they are in order relative to only each other (so for example 5,1,4,9,8 => 4,1,5,9,8). I am interested in the math behind how it is known that only 3 if statements are needed, since there are 3! (=6) permutations of 3 elements.
- theThe median is swapped so it's beside the largest valued element of the 3. Latter in the code I noticed
partitionIt()
hasint rightPtr = right - 1;
and I think the -1 is to avoid one extra iteration of the while loop as it's known [right-1] and [right] is a sorted sub array of size 2. Is this right? I don't really see how this benefits the algorithm as quicksort works on the principle of finding the final location of a pivot, and doesn't care a bout a sorted subarray.
Here is my code:
I'm not sure if I should be calling quicksort
recusivleyrecursively on quicksort(arr, beginning, partition);
quicksort(arr, beginning, partition);
or quicksort(arr, beginning, partition-1);
quicksort(arr, beginning, partition-1);
I randomly generate arrays and call quicksortquicksort
on them. The time is meausured and summed and at the end it is divided by the number of arrays that were tested (to give the average).
long startTime = System.nanoTime();
quicksort(randomArray, 0, randomArray.length-1);
long endTime = System.nanoTime();
totalTime += endTime-startTime;
For the method of choosing the first element as the pivot and iterating through 1,000,000 arrays of length 100 with random values between [-100, 100] it took: 9498ns, 9464ns, 9459ns.
- 9498ns
- 9464ns
- 9459ns
Doing this on arrays of length 10 gave the times: 623ns, 670ns, 914ns, 838ns, 635ns.
- 623ns
- 670ns
- 914ns
- 838ns
- 635ns
I ran extra tests as I was surprised to see such high variability. Why the variability?
For the tests run with the median with side effects implementation, on 1,000,000 randomly generated arrays of length 100 with values between [-100, 100] the results were: 8590ns, 8697ns, 8586 ns.
- 8590ns
- 8697ns
- 8586ns
For arrays of length 10 the results were: 655ns, 679ns, 660ns.
- 655ns
- 679ns
- 660ns
It doesn't look like choosing the pivot of median of 3, and presorting the 3, is much better than choosing the first element. In the future I'm going to write a pivot-choosing method that only takes the median of 3 and doesn't do the side-effect thing and see how fast it preforms. [1]: http://www.java2s.com/Tutorial/Java/0140__Collections/Quicksortwithmedianofthreepartitioning.htm