Skip to content

Commit d9c3374

Browse files
committed
Added GetPivot() method
Instead of quicksort's pivot always being the last element, there are now three options: last, random, or median-of-three (default).
1 parent a4e69bb commit d9c3374

File tree

1 file changed

+77
-11
lines changed

1 file changed

+77
-11
lines changed

compare-sorting-algorithms.cs

Lines changed: 77 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -405,7 +405,7 @@ private static void QuickSort(int[] array, int start, int end, bool printUpdates
405405
QuickSort(array, partitionIndex + 1, end, printUpdates);
406406
}
407407

408-
/* Sets pivot to the last element in given array, and partitionIndex to the first.
408+
/* Sets pivot to some element in the given array, and partitionIndex to the first.
409409
* Iterates through each element and compares against the pivot.
410410
* If it's less than or equal to the pivot, swap it with partitionIndex++.
411411
* If it's greater than pivot, leave it alone.
@@ -417,20 +417,23 @@ private static int Partition(int[] array, int start, int end, bool printUpdates)
417417
ulong comparisons = 0;
418418
ulong swaps = 0;
419419

420-
// Set pivot to end and partitionIndex to start
421-
int pivot = array[end];
420+
// Set pivot (one of three methods, see GetPivot method)
421+
int pivotIndex = GetPivot(array, start, end);
422+
int pivot = array[pivotIndex];
423+
// Set partitionIndex to start
422424
int partitionIndex = start;
425+
423426
if (printUpdates)
424-
Console.WriteLine("Pivot is {0}, move <= elements to left and > to right", pivot);
427+
Console.WriteLine("Pivot is {0}, move < elements to left and >= to right", pivot);
425428

426-
// Iterate from start to end
429+
// Iterate from start to end - 1 (because end is always the pivot)
427430
for (int i = start; i < end; i++)
428431
{
429432
// Compare each element to the pivot
430433
comparisons++;
431-
if (array[i] <= pivot)
434+
if (array[i] < pivot)
432435
{
433-
// If it's <= pivot, swap to left of partition
436+
// If it's < pivot, swap to left of partition
434437
Swap(array, i, partitionIndex);
435438
partitionIndex++;
436439
swaps++;
@@ -444,10 +447,73 @@ private static int Partition(int[] array, int start, int end, bool printUpdates)
444447
totalComparisonsQuick += comparisons;
445448
totalSwapsQuick += swaps;
446449

447-
PrintArray(array, "Pivot moved to index " + partitionIndex.ToString().PadLeft(2));
450+
string message = "Pivot was " + pivot.ToString().PadLeft(2) + ", moved to index " + partitionIndex.ToString().PadLeft(2);
451+
PrintArray(array, message);
448452
return partitionIndex;
449453
}
450454

455+
/* Returns the pivot for Quicksort's Partition method.
456+
* Choice of three methods of finding the pivot: end, random, and median-of-three
457+
* Choose by setting the value of 'pivotMethod' a few lines down.
458+
*
459+
* A note on median-of-three from Wikipedia:
460+
* "Although this approach optimizes quite well, it is typically outperformed in practice
461+
* by instead choosing random pivots, which has average linear time for selection and
462+
* average log-linear time for sorting, and avoids the overhead of computing the pivot."
463+
*/
464+
private static int GetPivot(int[] array, int start, int end)
465+
{
466+
int pivotMethod = 2; //Set here: 0 = end, 1 = random, 2 = median-of-three
467+
468+
// Method 1: Pivot = end
469+
// This gives Quicksort a running time O(n^2) in the worst case (already sorted)
470+
if (pivotMethod == 0)
471+
return end;
472+
473+
// Method 2: Pivot = random
474+
else if (pivotMethod == 1)
475+
{
476+
// Pivot is the element at a random index in this part of the array
477+
Random rnd = new Random();
478+
int i = rnd.Next(start, end + 1);
479+
480+
// Swap the pivot with the end (end is now pivot)
481+
Swap(array, i, end);
482+
totalSwapsQuick++;
483+
484+
return end;
485+
}
486+
487+
// Method 3: Pivot = 'median of three', change the array as required
488+
else
489+
{
490+
int mid = (start + end) / 2;
491+
492+
// Ensure start < mid < end
493+
if (array[start] > array[end])
494+
{
495+
Swap(array, start, end);
496+
totalSwapsQuick++;
497+
}
498+
if (array[start] > array[mid])
499+
{
500+
Swap(array, start, mid);
501+
totalSwapsQuick++;
502+
}
503+
if (array[mid] > array[end])
504+
{
505+
Swap(array, mid, end);
506+
totalSwapsQuick++;
507+
}
508+
509+
// Swap mid and end (end is now pivot)
510+
Swap(array, end, mid);
511+
totalSwapsQuick++;
512+
513+
return end;
514+
}
515+
}
516+
451517
/* Sorts an array using Mergesort algorithm, along with Merge().
452518
* Splits the array into two halves, then recursively calls Mergesort on each half.
453519
* Base case is when there's the array only contains one element (i.e. it must be sorted).
@@ -458,7 +524,7 @@ private static int Partition(int[] array, int start, int end, bool printUpdates)
458524
private static void MergeSort(int[] array, bool printUpdates)
459525
{
460526
int n = array.Length;
461-
int mid = n/2;
527+
int mid = n / 2;
462528

463529
// Base case
464530
if (n < 2)
@@ -499,7 +565,7 @@ private static void Merge(int[] array, int[] leftArray, int[] rightArray, bool p
499565
int r = 0; // index of right sub-array
500566
int m = 0; // index of merged array
501567

502-
568+
503569
// Copy the next value in left and right sub-arrays to the main array
504570
while (l < leftCount && r < rightCount)
505571
{
@@ -522,7 +588,7 @@ private static void Merge(int[] array, int[] leftArray, int[] rightArray, bool p
522588
swaps++;
523589
array[m++] = rightArray[r++];
524590
}
525-
591+
526592
if (printUpdates)
527593
PrintArray(array, "<- After a completed Merge of two sub-arrays");
528594

0 commit comments

Comments
 (0)