Vastly simplified the quicksort implementation (split out the partition sorting code into a separate method like most code examples did)

git-svn-id: file:///srv/devel/repo-conversion/nusu@340 d2e56fa2-650e-0410-a79f-9358c0239efd
This commit is contained in:
Markus Ewald 2022-11-03 11:33:16 +00:00
parent a10d30e6ea
commit 41691ddf94
3 changed files with 71 additions and 57 deletions

View File

@ -106,7 +106,9 @@
<DependentUpon>Deque.cs</DependentUpon> <DependentUpon>Deque.cs</DependentUpon>
</Compile> </Compile>
<Compile Include="Source\Collections\IListExtensions.cs" /> <Compile Include="Source\Collections\IListExtensions.cs" />
<Compile Include="Source\Collections\IListExtensions.Test.cs" /> <Compile Include="Source\Collections\IListExtensions.Test.cs">
<DependentUpon>IListExtensions.cs</DependentUpon>
</Compile>
<Compile Include="Source\Collections\IMultiDictionary.cs" /> <Compile Include="Source\Collections\IMultiDictionary.cs" />
<Compile Include="Source\Collections\IObservableCollection.cs" /> <Compile Include="Source\Collections\IObservableCollection.cs" />
<Compile Include="Source\Collections\IRecyclable.cs" /> <Compile Include="Source\Collections\IRecyclable.cs" />
@ -119,7 +121,9 @@
<DependentUpon>ItemReplaceEventArgs.cs</DependentUpon> <DependentUpon>ItemReplaceEventArgs.cs</DependentUpon>
</Compile> </Compile>
<Compile Include="Source\Collections\ListSegment.cs" /> <Compile Include="Source\Collections\ListSegment.cs" />
<Compile Include="Source\Collections\ListSegment.Test.cs" /> <Compile Include="Source\Collections\ListSegment.Test.cs">
<DependentUpon>ListSegment.cs</DependentUpon>
</Compile>
<Compile Include="Source\Collections\MultiDictionary.cs" /> <Compile Include="Source\Collections\MultiDictionary.cs" />
<Compile Include="Source\Collections\MultiDictionary.ValueCollection.cs"> <Compile Include="Source\Collections\MultiDictionary.ValueCollection.cs">
<DependentUpon>MultiDictionary.cs</DependentUpon> <DependentUpon>MultiDictionary.cs</DependentUpon>

View File

@ -66,7 +66,7 @@ namespace Nuclex.Support.Collections {
var testList = new List<int>(capacity: 5) { 1, 5, 2, 4, 3 }; var testList = new List<int>(capacity: 5) { 1, 5, 2, 4, 3 };
var testListAsIList = (IList<int>)testList; var testListAsIList = (IList<int>)testList;
testListAsIList.QuickSort(Comparer<int>.Default); testListAsIList.QuickSort();
CollectionAssert.AreEqual( CollectionAssert.AreEqual(
new List<int>(capacity: 5) { 1, 2, 3, 4, 5 }, new List<int>(capacity: 5) { 1, 2, 3, 4, 5 },

View File

@ -103,7 +103,7 @@ namespace Nuclex.Support.Collections {
/// <typeparam name="TElement">Type of elements the list contains</typeparam> /// <typeparam name="TElement">Type of elements the list contains</typeparam>
/// <param name="list">List in which a subset will be sorted</param> /// <param name="list">List in which a subset will be sorted</param>
public static void InsertionSort<TElement>(this IList<TElement> list) { public static void InsertionSort<TElement>(this IList<TElement> list) {
InsertionSort(list, Comparer<TElement>.Default); InsertionSort(list, 0, list.Count, Comparer<TElement>.Default);
} }
/// <summary> /// <summary>
@ -111,68 +111,78 @@ namespace Nuclex.Support.Collections {
/// </summary> /// </summary>
/// <typeparam name="TElement">Type of elements the list contains</typeparam> /// <typeparam name="TElement">Type of elements the list contains</typeparam>
/// <param name="list">List in which a subset will be sorted</param> /// <param name="list">List in which a subset will be sorted</param>
/// <param name="startIndex">Index at which the sorting process will begin</param>
/// <param name="count">Index one past the last element that will be sorted</param>
/// <param name="comparer">Comparison function to use for comparing list elements</param>
public static void QuickSort<TElement>(
this IList<TElement> list, int startIndex, int count, IComparer<TElement> comparer
) {
var remainingPartitions = new Stack<Partition>();
remainingPartitions.Push(new Partition(startIndex, startIndex + count - 1));
while(remainingPartitions.Count > 0) {
Partition current = remainingPartitions.Pop();
int leftEnd = current.LeftmostIndex;
int rightEnd = current.RightmostIndex;
int pivotIndex = quicksortPartition(list, leftEnd, rightEnd, comparer);
if(pivotIndex - 1 > leftEnd) {
remainingPartitions.Push(new Partition(leftEnd, pivotIndex - 1));
}
if(pivotIndex + 1 < rightEnd) {
remainingPartitions.Push(new Partition(pivotIndex + 1, rightEnd));
}
}
}
/// <summary>
/// Sorts all the elements in an IList&lt;T&gt; using the insertion sort algorithm
/// </summary>
/// <typeparam name="TElement">Type of elements the list contains</typeparam>
/// <param name="list">List in which a subset will be sorted</param>
/// <param name="comparer">Comparison function to use for comparing list elements</param> /// <param name="comparer">Comparison function to use for comparing list elements</param>
public static void QuickSort<TElement>( public static void QuickSort<TElement>(
this IList<TElement> list, IComparer<TElement> comparer this IList<TElement> list, IComparer<TElement> comparer
) { ) {
int rightIndex = list.Count - 1; QuickSort(list, 0, list.Count, comparer);
var remainingPartitions = new Stack<Partition>();
remainingPartitions.Push(new Partition(0, rightIndex));
while(remainingPartitions.Count > 0) {
Partition currentPartition = remainingPartitions.Pop();
int leftIndex = currentPartition.LeftmostIndex + 1;
int pivotIndex = currentPartition.LeftmostIndex;
rightIndex = currentPartition.RightmostIndex;
TElement pivot = list[pivotIndex];
if(leftIndex > rightIndex)
continue;
while(leftIndex < rightIndex) {
while(leftIndex <= rightIndex) {
if(comparer.Compare(list[leftIndex], pivot) > 0) {
break;
}
++leftIndex;
} }
while(leftIndex <= rightIndex) { /// <summary>
if(comparer.Compare(list[rightIndex], pivot) < 0) { /// Sorts all the elements in an IList&lt;T&gt; using the insertion sort algorithm
break; /// </summary>
/// <typeparam name="TElement">Type of elements the list contains</typeparam>
/// <param name="list">List in which a subset will be sorted</param>
public static void QuickSort<TElement>(this IList<TElement> list) {
QuickSort(list, 0, list.Count, Comparer<TElement>.Default);
} }
--rightIndex; private static int quicksortPartition<TElement>(
} IList<TElement> list, int firstIndex, int lastIndex, IComparer<TElement> comparer
) {
TElement pivot = list[lastIndex];
if(rightIndex >= leftIndex) { // Set the high index element to its proper sorted position
TElement temp = list[leftIndex]; int nextIndex = firstIndex;
list[leftIndex] = list[rightIndex]; for(int index = firstIndex; index < lastIndex; ++index) {
list[rightIndex] = temp; if(comparer.Compare(list[index], pivot) < 0) {
} TElement temp = list[nextIndex];
list[nextIndex] = list[index];
list[index] = temp;
} ++nextIndex;
if(pivotIndex <= rightIndex) {
if(comparer.Compare(list[pivotIndex], list[rightIndex]) > 0) {
TElement temp = list[pivotIndex];
list[pivotIndex] = list[rightIndex];
list[rightIndex] = temp;
} }
} }
if(currentPartition.LeftmostIndex < rightIndex) { // Set the high index value to its sorted position
remainingPartitions.Push(new Partition(currentPartition.LeftmostIndex, rightIndex - 1)); {
TElement temp = list[nextIndex];
list[nextIndex] = list[lastIndex];
list[lastIndex] = temp;
} }
if(currentPartition.RightmostIndex > rightIndex) { // Returns the next sorting element location
remainingPartitions.Push(new Partition(rightIndex + 1, currentPartition.RightmostIndex)); return nextIndex;
}
}
} }
} }