Sorting algorithms/Quicksort: Difference between revisions
Content deleted Content added
Alextretyak (talk | contribs) Added 11l |
Opted for linear interpolation, to remove the dependency on Math.Random, when obtaining samples for estimation of a median by pivot(). The median is now returned and passed via locals, rather than a property. |
||
Line 1,784: | Line 1,784: | ||
#define Tripartite |
#define Tripartite |
||
namespace |
namespace RosettaCode { |
||
using System; |
using System; |
||
using System.Diagnostics; |
using System.Diagnostics; |
||
class QuickSort<T> where T : IComparable { |
public class QuickSort<T> where T : IComparable { |
||
#region Constants |
#region Constants |
||
public const Int32 INSERTION_LIMIT_DEFAULT = 12; |
|||
private const Int32 SAMPLES_MAX = 19; |
|||
#endregion |
#endregion |
||
#region Properties |
#region Properties |
||
public Int32 InsertionLimit { get; |
public Int32 InsertionLimit { get; init; } |
||
private |
private T[] Samples { get; init; } |
||
private T Median { get; set; } |
|||
private Int32 Left { get; set; } |
private Int32 Left { get; set; } |
||
private Int32 Right { get; set; } |
private Int32 Right { get; set; } |
||
Line 1,805: | Line 1,804: | ||
#region Constructors |
#region Constructors |
||
public QuickSort(Int32 insertionLimit |
public QuickSort(Int32 insertionLimit = INSERTION_LIMIT_DEFAULT) { |
||
this.InsertionLimit = insertionLimit; |
this.InsertionLimit = insertionLimit; |
||
this. |
this.Samples = new T[SAMPLES_MAX]; |
||
⚫ | |||
public QuickSort(Int32 insertionLimit) |
|||
: this(insertionLimit, new Random()) { |
|||
⚫ | |||
public QuickSort() |
|||
: this(INSERTION_LIMIT_DEFAULT) { |
|||
} |
} |
||
#endregion |
#endregion |
||
Line 1,834: | Line 1,825: | ||
Left = first; |
Left = first; |
||
Right = last; |
Right = last; |
||
pivot(entries); |
var median = pivot(entries); |
||
partition(entries); |
partition(median, entries); |
||
//[Note]Right < Left |
//[Note]Right < Left |
||
Line 1,858: | Line 1,849: | ||
} |
} |
||
private |
private static Int32 sampleSize(Int32 length) { |
||
⚫ | |||
// |
// |
||
// An odd sample size is chosen based on the log of the interval size. |
// An odd sample size is chosen based on the log of the interval size. |
||
Line 1,864: | Line 1,856: | ||
// an estimate of the true median. |
// an estimate of the true median. |
||
// |
// |
||
var samples = Math.Min(2 * logLen + 1, SAMPLES_MAX); |
|||
return Math.Min(samples, length); |
|||
⚫ | |||
/// <summary>Estimate the median value of entries[Left:Right]</summary> |
|||
private T pivot(T[] entries) { |
|||
var length = Right + 1 - Left; |
var length = Right + 1 - Left; |
||
var |
var samples = sampleSize(length); |
||
var |
for (var sample = 0; sample < samples; sample++) { |
||
⚫ | |||
⚫ | |||
var |
var index = length * sample / samples + Left; |
||
⚫ | |||
⚫ | |||
for (var first = Left; first <= last; first++) { |
|||
// Random sampling avoids pathological cases |
|||
var random = Random.Next(first, Right + 1); |
|||
Swap(entries, first, random); |
|||
} |
} |
||
⚫ | |||
var middle = samples / 2; |
|||
⚫ | |||
return Samples[middle]; |
|||
} |
} |
||
private void partition(T[] entries) { |
private void partition(T median, T[] entries) { |
||
var first = Left; |
var first = Left; |
||
var last = Right; |
var last = Right; |
||
Line 1,888: | Line 1,882: | ||
#endif |
#endif |
||
while (true) { |
while (true) { |
||
//[Assert]There exists some index >= Left where entries[index] >= |
//[Assert]There exists some index >= Left where entries[index] >= median |
||
//[Assert]There exists some index <= Right where entries[index] <= |
//[Assert]There exists some index <= Right where entries[index] <= median |
||
// So, there is no need for Left or Right bound checks |
// So, there is no need for Left or Right bound checks |
||
while ( |
while (median.CompareTo(entries[Left]) > 0) Left++; |
||
while ( |
while (median.CompareTo(entries[Right]) < 0) Right--; |
||
//[Assert]entries[Right] <= |
//[Assert]entries[Right] <= median <= entries[Left] |
||
if (Right <= Left) break; |
if (Right <= Left) break; |
||
Swap(entries, Left, Right); |
Swap(entries, Left, Right); |
||
swapOut(entries); |
swapOut(median, entries); |
||
Left++; |
Left++; |
||
Right--; |
Right--; |
||
//[Assert]entries[first:Left - 1] <= |
//[Assert]entries[first:Left - 1] <= median <= entries[Right + 1:last] |
||
} |
} |
||
Line 1,911: | Line 1,905: | ||
swapIn(entries, first, last); |
swapIn(entries, first, last); |
||
//[Assert]entries[first:Right] <= |
//[Assert]entries[first:Right] <= median <= entries[Left:last] |
||
//[Assert]entries[Right + 1:Left - 1] == |
//[Assert]entries[Right + 1:Left - 1] == median when non-empty |
||
} |
} |
||
#endregion |
#endregion |
||
Line 1,918: | Line 1,912: | ||
#region Swap Methods |
#region Swap Methods |
||
[Conditional("Tripartite")] |
[Conditional("Tripartite")] |
||
private void swapOut(T[] entries) { |
private void swapOut(T median, T[] entries) { |
||
if ( |
if (median.CompareTo(entries[Left]) == 0) Swap(entries, LeftMedian++, Left); |
||
if ( |
if (median.CompareTo(entries[Right]) == 0) Swap(entries, Right, RightMedian--); |
||
} |
} |
||
Line 1,930: | Line 1,924: | ||
} |
} |
||
/// <summary>Swap entries at the left and right indicies.</summary> |
|||
⚫ | |||
if (index1 != index2) { |
|||
Swap(ref entries[left], ref entries[right]); |
|||
⚫ | |||
entries[index1] = entries[index2]; |
|||
⚫ | |||
/// <summary>Swap two entities of type T.</summary> |
|||
⚫ | |||
public static void Swap(ref T e1, ref T e2) { |
|||
var e = e1; |
|||
e1 = e2; |
|||
⚫ | |||
} |
} |
||
#endregion |
#endregion |
||
Line 1,943: | Line 1,941: | ||
static class InsertionSort<T> where T : IComparable { |
static class InsertionSort<T> where T : IComparable { |
||
public static void Sort(T[] entries, Int32 first, Int32 last) { |
public static void Sort(T[] entries, Int32 first, Int32 last) { |
||
for (var |
for (var next = first + 1; next <= last; next++) |
||
insert(entries, first, |
insert(entries, first, next); |
||
} |
} |
||
/// <summary>Bubble next entry up to its sorted location, assuming entries[first:next - 1] are already sorted.</summary> |
|||
⚫ | |||
private static void insert(T[] entries, Int32 first, Int32 next) { |
|||
⚫ | |||
var entry = entries[next]; |
|||
while (next > first && entries[next - 1].CompareTo(entry) > 0) |
|||
entries[ |
entries[next] = entries[--next]; |
||
⚫ | |||
} |
} |
||
} |
} |