QuickSort methods extracted to their own extension class.
This commit is contained in:
1 parent
7434b28894
commit
f928e1e35e
5 files changed
+141
-121
No files matched your search
@@ -0,0 +1,132 @@
|
||||
// Ignore Spelling: Linq
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
// The source code was taken from
|
||||
// https://codereview.stackexchange.com/questions/205407/quicksort-without-recursion.
|
||||
//
|
||||
// It was only beautified for .Net 6.0+.
|
||||
|
||||
namespace Recyclable.Collections.Linq
|
||||
{
|
||||
internal static class QuickSortExtensions<T>
|
||||
{
|
||||
|
||||
public static void InsertionSort(IList<T> values, int startIndex, int endIndex, IComparer<T> comparer)
|
||||
{
|
||||
var left = startIndex;
|
||||
while (left < endIndex)
|
||||
{
|
||||
int right = left;
|
||||
T? temp = values[++left];
|
||||
while (right >= startIndex && 0 < comparer.Compare(values[right], temp))
|
||||
{
|
||||
values[right + 1] = values[right--];
|
||||
}
|
||||
|
||||
values[right + 1] = temp;
|
||||
}
|
||||
}
|
||||
|
||||
public static void InsertionSort(IList<T> values, IComparer<T> comparer)
|
||||
{
|
||||
InsertionSort(values, 0, values.Count - 1, comparer);
|
||||
}
|
||||
|
||||
public static void InsertionSort(IList<T> values)
|
||||
{
|
||||
InsertionSort(values, Comparer<T>.Default);
|
||||
}
|
||||
|
||||
public static void QuickSort(IList<T> values, int startIndex, int endIndex, IComparer<T> comparer, IRandomNumberGenerator randomNumberGenerator)
|
||||
{
|
||||
var range = (startIndex, endIndex);
|
||||
var stack = new Stack<(int, int)>();
|
||||
|
||||
do
|
||||
{
|
||||
startIndex = range.startIndex;
|
||||
endIndex = range.endIndex;
|
||||
|
||||
if (endIndex - startIndex + 1 < 31)
|
||||
{
|
||||
InsertionSort(values, startIndex, endIndex, comparer);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
var pivot = SampleMedian(values, startIndex, endIndex, comparer, randomNumberGenerator);
|
||||
var left = startIndex;
|
||||
var right = endIndex;
|
||||
|
||||
while (left <= right)
|
||||
{
|
||||
while (0 > comparer.Compare(values[left], pivot))
|
||||
{
|
||||
left++;
|
||||
}
|
||||
|
||||
while (0 > comparer.Compare(pivot, values[right]))
|
||||
{
|
||||
right--;
|
||||
}
|
||||
|
||||
if (left <= right)
|
||||
{
|
||||
Swap(values, left++, right--);
|
||||
}
|
||||
}
|
||||
|
||||
if (startIndex < right)
|
||||
{
|
||||
stack.Push((startIndex, right));
|
||||
}
|
||||
|
||||
if (left < endIndex)
|
||||
{
|
||||
stack.Push((left, endIndex));
|
||||
}
|
||||
}
|
||||
while (stack.TryPop(out range));
|
||||
}
|
||||
|
||||
public static void QuickSort(IList<T> values, IComparer<T> comparer, IRandomNumberGenerator randomNumberGenerator)
|
||||
=> QuickSort(values, 0, values.Count - 1, comparer, randomNumberGenerator);
|
||||
|
||||
public static void QuickSort(IList<T> values)
|
||||
=> QuickSort(values, Comparer<T>.Default, new SystemRandomNumberGenerator());
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static T SampleMedian(IList<T> values, int startIndex, int endIndex, IComparer<T> comparer, IRandomNumberGenerator randomNumberGenerator)
|
||||
{
|
||||
var left = randomNumberGenerator.NextInt32(startIndex, endIndex);
|
||||
var middle = randomNumberGenerator.NextInt32(startIndex, endIndex);
|
||||
var right = randomNumberGenerator.NextInt32(startIndex, endIndex);
|
||||
|
||||
if (0 > comparer.Compare(values[right], values[left]))
|
||||
{
|
||||
Swap(values, right, left);
|
||||
}
|
||||
|
||||
if (0 > comparer.Compare(values[middle], values[left]))
|
||||
{
|
||||
Swap(values, middle, left);
|
||||
}
|
||||
|
||||
if (0 > comparer.Compare(values[right], values[middle]))
|
||||
{
|
||||
Swap(values, right, middle);
|
||||
}
|
||||
|
||||
return values[middle];
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static void Swap(IList<T> values, int xIndex, int yIndex)
|
||||
=> (values[yIndex], values[xIndex]) = (values[xIndex], values[yIndex]);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,4 @@
|
||||
using System.Buffers;
|
||||
using System.Numerics;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Recyclable.Collections.Pools;
|
||||
|
||||
namespace Recyclable.Collections
|
||||
@@ -85,32 +83,6 @@ namespace Recyclable.Collections
|
||||
}
|
||||
}
|
||||
|
||||
public static void InsertionSort(IList<T> values, int startIndex, int endIndex, IComparer<T> comparer)
|
||||
{
|
||||
var left = startIndex;
|
||||
while (left < endIndex)
|
||||
{
|
||||
int right = left;
|
||||
T? temp = values[++left];
|
||||
while (right >= startIndex && 0 < comparer.Compare(values[right], temp))
|
||||
{
|
||||
values[right + 1] = values[right--];
|
||||
}
|
||||
|
||||
values[right + 1] = temp;
|
||||
}
|
||||
}
|
||||
|
||||
public static void InsertionSort(IList<T> values, IComparer<T> comparer)
|
||||
{
|
||||
InsertionSort(values, 0, values.Count - 1, comparer);
|
||||
}
|
||||
|
||||
public static void InsertionSort(IList<T> values)
|
||||
{
|
||||
InsertionSort(values, Comparer<T>.Default);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static long LongIndexOf(RecyclableList<T[]> arrays, int blockSize, T item, IEqualityComparer<T> comparer)
|
||||
{
|
||||
@@ -130,90 +102,6 @@ namespace Recyclable.Collections
|
||||
return -1;
|
||||
}
|
||||
|
||||
// The source code was taken from https://codereview.stackexchange.com/questions/205407/quicksort-without-recursion.
|
||||
// It was only beautified for .Net 6.0+.
|
||||
public static void QuickSort(IList<T> values, int startIndex, int endIndex, IComparer<T> comparer, IRandomNumberGenerator randomNumberGenerator)
|
||||
{
|
||||
var range = (startIndex, endIndex);
|
||||
var stack = new Stack<(int, int)>();
|
||||
|
||||
do
|
||||
{
|
||||
startIndex = range.startIndex;
|
||||
endIndex = range.endIndex;
|
||||
|
||||
if (endIndex - startIndex + 1 < 31)
|
||||
{
|
||||
InsertionSort(values, startIndex, endIndex, comparer);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
var pivot = SampleMedian(values, startIndex, endIndex, comparer, randomNumberGenerator);
|
||||
var left = startIndex;
|
||||
var right = endIndex;
|
||||
|
||||
while (left <= right)
|
||||
{
|
||||
while (0 > comparer.Compare(values[left], pivot))
|
||||
{
|
||||
left++;
|
||||
}
|
||||
|
||||
while (0 > comparer.Compare(pivot, values[right]))
|
||||
{
|
||||
right--;
|
||||
}
|
||||
|
||||
if (left <= right)
|
||||
{
|
||||
Swap(values, left++, right--);
|
||||
}
|
||||
}
|
||||
|
||||
if (startIndex < right)
|
||||
{
|
||||
stack.Push((startIndex, right));
|
||||
}
|
||||
|
||||
if (left < endIndex)
|
||||
{
|
||||
stack.Push((left, endIndex));
|
||||
}
|
||||
}
|
||||
while (stack.TryPop(out range));
|
||||
}
|
||||
public static void QuickSort(IList<T> values, IComparer<T> comparer, IRandomNumberGenerator randomNumberGenerator)
|
||||
=> QuickSort(values, 0, values.Count - 1, comparer, randomNumberGenerator);
|
||||
|
||||
public static void QuickSort(IList<T> values)
|
||||
=> QuickSort(values, Comparer<T>.Default, new SystemRandomNumberGenerator());
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static T SampleMedian(IList<T> values, int startIndex, int endIndex, IComparer<T> comparer, IRandomNumberGenerator randomNumberGenerator)
|
||||
{
|
||||
var left = randomNumberGenerator.NextInt32(startIndex, endIndex);
|
||||
var middle = randomNumberGenerator.NextInt32(startIndex, endIndex);
|
||||
var right = randomNumberGenerator.NextInt32(startIndex, endIndex);
|
||||
|
||||
if (0 > comparer.Compare(values[right], values[left]))
|
||||
{
|
||||
Swap(values, right, left);
|
||||
}
|
||||
|
||||
if (0 > comparer.Compare(values[middle], values[left]))
|
||||
{
|
||||
Swap(values, middle, left);
|
||||
}
|
||||
|
||||
if (0 > comparer.Compare(values[right], values[middle]))
|
||||
{
|
||||
Swap(values, right, middle);
|
||||
}
|
||||
|
||||
return values[middle];
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
public static void ResizeAndCopy(RecyclableList<T> list)
|
||||
{
|
||||
@@ -267,9 +155,5 @@ namespace Recyclable.Collections
|
||||
|
||||
return newSize;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static void Swap(IList<T> values, int xIndex, int yIndex)
|
||||
=> (values[yIndex], values[xIndex]) = (values[xIndex], values[yIndex]);
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,6 @@
|
||||
namespace Recyclable.Collections
|
||||
using Recyclable.Collections.Linq;
|
||||
|
||||
namespace Recyclable.Collections
|
||||
{
|
||||
internal class RecyclableSortedList<TKey, TValue> : RecyclableLongList<(TKey Key, TValue Value)>
|
||||
where TKey : notnull
|
||||
@@ -68,7 +70,7 @@
|
||||
BeginUpdate();
|
||||
try
|
||||
{
|
||||
RecyclableListHelpers<(TKey, TValue)>.QuickSort(this, _comparer, _randomNumberGenerator);
|
||||
QuickSortExtensions<(TKey, TValue)>.QuickSort(this, _comparer, _randomNumberGenerator);
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using FluentAssertions;
|
||||
using Recyclable.Collections;
|
||||
using Recyclable.Collections.Linq;
|
||||
|
||||
#pragma warning disable xUnit1026, RCS1163, IDE0060, RCS1235
|
||||
|
||||
@@ -424,7 +425,7 @@ namespace Recyclable.CollectionsTests
|
||||
|
||||
// Act
|
||||
using RecyclableList<long> list = new(testData);
|
||||
RecyclableListHelpers<long>.QuickSort(list);
|
||||
QuickSortExtensions<long>.QuickSort(list);
|
||||
|
||||
// Validate
|
||||
_ = list.Count.Should().Be((int)itemsCount);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using FluentAssertions;
|
||||
using Recyclable.Collections;
|
||||
using Recyclable.Collections.Linq;
|
||||
|
||||
#pragma warning disable xUnit1026, RCS1163, IDE0060, RCS1235
|
||||
|
||||
@@ -481,7 +482,7 @@ namespace Recyclable.CollectionsTests
|
||||
|
||||
// Act
|
||||
using RecyclableLongList<long> list = new(testData, minBlockSize: targetBlockSize);
|
||||
RecyclableListHelpers<long>.QuickSort(list);
|
||||
QuickSortExtensions<long>.QuickSort(list);
|
||||
|
||||
// Validate
|
||||
_ = list.LongCount.Should().Be(itemsCount);
|
||||
|
||||
Reference in new issue
Block a user