@@ -405,7 +405,7 @@ private static void QuickSort(int[] array, int start, int end, bool printUpdates
405
405
QuickSort ( array , partitionIndex + 1 , end , printUpdates ) ;
406
406
}
407
407
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.
409
409
* Iterates through each element and compares against the pivot.
410
410
* If it's less than or equal to the pivot, swap it with partitionIndex++.
411
411
* 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)
417
417
ulong comparisons = 0 ;
418
418
ulong swaps = 0 ;
419
419
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
422
424
int partitionIndex = start ;
425
+
423
426
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 ) ;
425
428
426
- // Iterate from start to end
429
+ // Iterate from start to end - 1 (because end is always the pivot)
427
430
for ( int i = start ; i < end ; i ++ )
428
431
{
429
432
// Compare each element to the pivot
430
433
comparisons ++ ;
431
- if ( array [ i ] <= pivot )
434
+ if ( array [ i ] < pivot )
432
435
{
433
- // If it's <= pivot, swap to left of partition
436
+ // If it's < pivot, swap to left of partition
434
437
Swap ( array , i , partitionIndex ) ;
435
438
partitionIndex ++ ;
436
439
swaps ++ ;
@@ -444,10 +447,73 @@ private static int Partition(int[] array, int start, int end, bool printUpdates)
444
447
totalComparisonsQuick += comparisons ;
445
448
totalSwapsQuick += swaps ;
446
449
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 ) ;
448
452
return partitionIndex ;
449
453
}
450
454
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
+
451
517
/* Sorts an array using Mergesort algorithm, along with Merge().
452
518
* Splits the array into two halves, then recursively calls Mergesort on each half.
453
519
* 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)
458
524
private static void MergeSort ( int [ ] array , bool printUpdates )
459
525
{
460
526
int n = array . Length ;
461
- int mid = n / 2 ;
527
+ int mid = n / 2 ;
462
528
463
529
// Base case
464
530
if ( n < 2 )
@@ -499,7 +565,7 @@ private static void Merge(int[] array, int[] leftArray, int[] rightArray, bool p
499
565
int r = 0 ; // index of right sub-array
500
566
int m = 0 ; // index of merged array
501
567
502
-
568
+
503
569
// Copy the next value in left and right sub-arrays to the main array
504
570
while ( l < leftCount && r < rightCount )
505
571
{
@@ -522,7 +588,7 @@ private static void Merge(int[] array, int[] leftArray, int[] rightArray, bool p
522
588
swaps ++ ;
523
589
array [ m ++ ] = rightArray [ r ++ ] ;
524
590
}
525
-
591
+
526
592
if ( printUpdates )
527
593
PrintArray ( array , "<- After a completed Merge of two sub-arrays" ) ;
528
594
0 commit comments