upload
This commit is contained in:
31
Strategies/CommunistSortStrategy.cs
Normal file
31
Strategies/CommunistSortStrategy.cs
Normal file
@@ -0,0 +1,31 @@
|
||||
using Lab9.Models;
|
||||
using Lab9.Services;
|
||||
|
||||
namespace Lab9.Strategies;
|
||||
|
||||
public class CommunistSortStrategy : SortStrategyBase
|
||||
{
|
||||
public override string Name => "Коммунистическая сортировка";
|
||||
|
||||
protected override void ExecuteCore(int[] array, SortMetrics metrics, StepLogger? logger)
|
||||
{
|
||||
if (array.Length == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var average = (int)(array.Sum(x => (long)x) / array.Length);
|
||||
|
||||
logger?.Line($"Среднее значение массива: {average}.");
|
||||
logger?.Line("Последовательно приводим элементы массива к общему значению.");
|
||||
logger?.BlankLine();
|
||||
|
||||
for (var i = 0; i < array.Length; i++)
|
||||
{
|
||||
var oldValue = array[i];
|
||||
logger?.Line($"Уравниваем индекс {i}: {oldValue} -> {average}.");
|
||||
Assign(array, i, average, metrics);
|
||||
logger?.ArrayState(array, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
10
Strategies/ISortStrategy.cs
Normal file
10
Strategies/ISortStrategy.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
using Lab9.Models;
|
||||
|
||||
namespace Lab9.Strategies;
|
||||
|
||||
public interface ISortStrategy
|
||||
{
|
||||
string Name { get; }
|
||||
|
||||
SortResult Sort(int[] source, bool ascending, bool enableLogging);
|
||||
}
|
||||
94
Strategies/MsdRadixSortStrategy.cs
Normal file
94
Strategies/MsdRadixSortStrategy.cs
Normal file
@@ -0,0 +1,94 @@
|
||||
using Lab9.Models;
|
||||
using Lab9.Services;
|
||||
|
||||
namespace Lab9.Strategies;
|
||||
|
||||
public class MsdRadixSortStrategy : SortStrategyBase
|
||||
{
|
||||
private const int AlphabetSize = 256;
|
||||
private const int Cutoff = 16;
|
||||
|
||||
public override string Name => "MSD Radix Sort";
|
||||
|
||||
protected override void ExecuteCore(int[] array, SortMetrics metrics, StepLogger? logger)
|
||||
{
|
||||
if (array.Length <= 1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var aux = new int[array.Length];
|
||||
Sort(array, 0, array.Length - 1, 3, aux, metrics, logger);
|
||||
}
|
||||
|
||||
private static void Sort(
|
||||
int[] array,
|
||||
int left,
|
||||
int right,
|
||||
int byteIndex,
|
||||
int[] aux,
|
||||
SortMetrics metrics,
|
||||
StepLogger? logger)
|
||||
{
|
||||
if (right <= left || byteIndex < 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (right - left <= Cutoff)
|
||||
{
|
||||
logger?.Line($"MSD: маленький диапазон [{left}; {right}], переключаемся на сортировку вставками.");
|
||||
InsertionSortRange(array, left, right, metrics, logger, "MSD/Insertion");
|
||||
logger?.BlankLine();
|
||||
return;
|
||||
}
|
||||
|
||||
logger?.Line($"MSD: обрабатываем диапазон [{left}; {right}], байт №{byteIndex}.");
|
||||
var count = new int[AlphabetSize + 2];
|
||||
|
||||
for (var i = left; i <= right; i++)
|
||||
{
|
||||
var digit = GetByte(array[i], byteIndex);
|
||||
count[digit + 2]++;
|
||||
}
|
||||
|
||||
for (var r = 0; r < AlphabetSize + 1; r++)
|
||||
{
|
||||
count[r + 1] += count[r];
|
||||
}
|
||||
|
||||
var starts = count.ToArray();
|
||||
|
||||
for (var i = left; i <= right; i++)
|
||||
{
|
||||
var digit = GetByte(array[i], byteIndex);
|
||||
aux[count[digit + 1]++] = array[i];
|
||||
metrics.AddMove();
|
||||
}
|
||||
|
||||
for (var i = left; i <= right; i++)
|
||||
{
|
||||
Assign(array, i, aux[i - left], metrics);
|
||||
}
|
||||
|
||||
logger?.ArrayState(array);
|
||||
logger?.BlankLine();
|
||||
|
||||
for (var r = 0; r < AlphabetSize; r++)
|
||||
{
|
||||
var start = left + starts[r];
|
||||
var end = left + starts[r + 1] - 1;
|
||||
|
||||
if (start < end)
|
||||
{
|
||||
Sort(array, start, end, byteIndex - 1, aux, metrics, logger);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static int GetByte(int value, int byteIndex)
|
||||
{
|
||||
var normalized = unchecked((uint)(value ^ int.MinValue));
|
||||
return (int)((normalized >> (byteIndex * 8)) & 0xFF);
|
||||
}
|
||||
}
|
||||
117
Strategies/SortStrategyBase.cs
Normal file
117
Strategies/SortStrategyBase.cs
Normal file
@@ -0,0 +1,117 @@
|
||||
using Lab9.Models;
|
||||
using Lab9.Services;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Lab9.Strategies;
|
||||
|
||||
public abstract class SortStrategyBase : ISortStrategy
|
||||
{
|
||||
public abstract string Name { get; }
|
||||
|
||||
public SortResult Sort(int[] source, bool ascending, bool enableLogging)
|
||||
{
|
||||
var array = source.ToArray();
|
||||
var metrics = new SortMetrics();
|
||||
var logger = enableLogging ? new StepLogger() : null;
|
||||
|
||||
logger?.Header($"Алгоритм: {Name}");
|
||||
logger?.Line($"Режим: {(ascending ? "По возрастанию" : "По убыванию")}");
|
||||
logger?.Line("Исходное состояние массива:");
|
||||
logger?.ArrayState(array);
|
||||
logger?.BlankLine();
|
||||
|
||||
var stopwatch = Stopwatch.StartNew();
|
||||
ExecuteCore(array, metrics, logger);
|
||||
|
||||
if (!ascending && array.Length > 1)
|
||||
{
|
||||
logger?.Line("Дополнительный этап: разворот массива для режима по убыванию.");
|
||||
Reverse(array, 0, array.Length - 1, metrics, logger);
|
||||
logger?.ArrayState(array);
|
||||
logger?.BlankLine();
|
||||
}
|
||||
|
||||
stopwatch.Stop();
|
||||
|
||||
logger?.Line("Финальный результат:");
|
||||
logger?.ArrayState(array);
|
||||
|
||||
return new SortResult
|
||||
{
|
||||
AlgorithmName = Name,
|
||||
SortedArray = array,
|
||||
Metrics = metrics,
|
||||
Elapsed = stopwatch.Elapsed,
|
||||
Log = logger?.ToString() ?? string.Empty
|
||||
};
|
||||
}
|
||||
|
||||
protected abstract void ExecuteCore(int[] array, SortMetrics metrics, StepLogger? logger);
|
||||
|
||||
protected static int Compare(int left, int right, SortMetrics metrics)
|
||||
{
|
||||
metrics.AddComparison();
|
||||
return left.CompareTo(right);
|
||||
}
|
||||
|
||||
protected static void Assign(int[] array, int index, int value, SortMetrics metrics)
|
||||
{
|
||||
array[index] = value;
|
||||
metrics.AddMove();
|
||||
}
|
||||
|
||||
protected static void Swap(int[] array, int left, int right, SortMetrics metrics)
|
||||
{
|
||||
if (left == right)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
(array[left], array[right]) = (array[right], array[left]);
|
||||
metrics.AddMove(3);
|
||||
}
|
||||
|
||||
protected static void Reverse(int[] array, int left, int right, SortMetrics metrics, StepLogger? logger)
|
||||
{
|
||||
while (left < right)
|
||||
{
|
||||
logger?.Line($"Меняем местами {array[left]} и {array[right]}.");
|
||||
|
||||
Swap(array, left, right, metrics);
|
||||
logger?.ArrayState(array, left, right);
|
||||
|
||||
left++;
|
||||
right--;
|
||||
}
|
||||
}
|
||||
|
||||
protected static void InsertionSortRange(
|
||||
int[] array,
|
||||
int left,
|
||||
int right,
|
||||
SortMetrics metrics,
|
||||
StepLogger? logger,
|
||||
string prefix)
|
||||
{
|
||||
for (var i = left + 1; i <= right; i++)
|
||||
{
|
||||
var current = array[i];
|
||||
var j = i - 1;
|
||||
|
||||
logger?.Line($"{prefix}: берём элемент {current}.");
|
||||
|
||||
while (j >= left && Compare(array[j], current, metrics) > 0)
|
||||
{
|
||||
logger?.Line($"Сравниваем {array[j]} и {current}. Сдвигаем {array[j]} вправо.");
|
||||
|
||||
Assign(array, j + 1, array[j], metrics);
|
||||
logger?.ArrayState(array, j, j + 1);
|
||||
j--;
|
||||
}
|
||||
|
||||
logger?.Line($"Ставим элемент {current} на место.");
|
||||
Assign(array, j + 1, current, metrics);
|
||||
logger?.ArrayState(array, j + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
758
Strategies/TimSortStrategy.cs
Normal file
758
Strategies/TimSortStrategy.cs
Normal file
@@ -0,0 +1,758 @@
|
||||
using Lab9.Models;
|
||||
using Lab9.Services;
|
||||
|
||||
namespace Lab9.Strategies;
|
||||
|
||||
public class TimSortStrategy : SortStrategyBase
|
||||
{
|
||||
private const int MinMerge = 32;
|
||||
private const int InitialMinGallop = 7;
|
||||
|
||||
private int[] _array = Array.Empty<int>();
|
||||
private int[] _temp = Array.Empty<int>();
|
||||
private int _minGallop;
|
||||
private readonly List<RunInfo> _runs = new();
|
||||
|
||||
private SortMetrics? _metrics;
|
||||
private StepLogger? _logger;
|
||||
|
||||
private struct RunInfo
|
||||
{
|
||||
public int Base;
|
||||
public int Length;
|
||||
|
||||
public RunInfo(int runBase, int runLength)
|
||||
{
|
||||
Base = runBase;
|
||||
Length = runLength;
|
||||
}
|
||||
}
|
||||
|
||||
public override string Name => "TimSort";
|
||||
|
||||
protected override void ExecuteCore(int[] array, SortMetrics metrics, StepLogger? logger)
|
||||
{
|
||||
if (array.Length <= 1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_array = array;
|
||||
_metrics = metrics;
|
||||
_logger = logger;
|
||||
_minGallop = InitialMinGallop;
|
||||
_runs.Clear();
|
||||
_temp = Array.Empty<int>();
|
||||
|
||||
var minRun = MinRunLength(array.Length);
|
||||
|
||||
logger?.Line($"TimSort: вычисленный minrun = {minRun}.");
|
||||
logger?.BlankLine();
|
||||
|
||||
var lo = 0;
|
||||
var remaining = array.Length;
|
||||
|
||||
while (remaining > 0)
|
||||
{
|
||||
var runLength = CountRunAndMakeAscending(lo, array.Length);
|
||||
|
||||
logger?.Line($"Найдена серия [{lo}; {lo + runLength - 1}] длиной {runLength}.");
|
||||
|
||||
if (runLength < minRun)
|
||||
{
|
||||
var forcedLength = remaining <= minRun ? remaining : minRun;
|
||||
logger?.Line($"Увеличиваем серию до {forcedLength} бинарными вставками.");
|
||||
BinaryInsertionSort(lo, lo + forcedLength, lo + runLength);
|
||||
runLength = forcedLength;
|
||||
logger?.ArrayState(_array);
|
||||
}
|
||||
|
||||
PushRun(lo, runLength);
|
||||
MergeCollapse();
|
||||
|
||||
lo += runLength;
|
||||
remaining -= runLength;
|
||||
|
||||
logger?.BlankLine();
|
||||
}
|
||||
|
||||
MergeForceCollapse();
|
||||
}
|
||||
|
||||
private static int MinRunLength(int n)
|
||||
{
|
||||
var r = 0;
|
||||
|
||||
while (n >= MinMerge)
|
||||
{
|
||||
r |= n & 1;
|
||||
n >>= 1;
|
||||
}
|
||||
|
||||
return n + r;
|
||||
}
|
||||
|
||||
private int CountRunAndMakeAscending(int lo, int hi)
|
||||
{
|
||||
var metrics = _metrics!;
|
||||
var logger = _logger;
|
||||
|
||||
var runHi = lo + 1;
|
||||
if (runHi == hi)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (Compare(_array[runHi], _array[lo], metrics) < 0)
|
||||
{
|
||||
runHi++;
|
||||
|
||||
while (runHi < hi && Compare(_array[runHi], _array[runHi - 1], metrics) < 0)
|
||||
{
|
||||
runHi++;
|
||||
}
|
||||
|
||||
logger?.Line($"Серия [{lo}; {runHi - 1}] убывающая. Разворачиваем.");
|
||||
Reverse(_array, lo, runHi - 1, metrics, logger);
|
||||
}
|
||||
else
|
||||
{
|
||||
runHi++;
|
||||
|
||||
while (runHi < hi && Compare(_array[runHi], _array[runHi - 1], metrics) >= 0)
|
||||
{
|
||||
runHi++;
|
||||
}
|
||||
}
|
||||
|
||||
return runHi - lo;
|
||||
}
|
||||
|
||||
private void BinaryInsertionSort(int lo, int hi, int start)
|
||||
{
|
||||
var metrics = _metrics!;
|
||||
var logger = _logger;
|
||||
|
||||
if (start == lo)
|
||||
{
|
||||
start++;
|
||||
}
|
||||
|
||||
for (var i = start; i < hi; i++)
|
||||
{
|
||||
var pivot = _array[i];
|
||||
var left = lo;
|
||||
var right = i;
|
||||
|
||||
while (left < right)
|
||||
{
|
||||
var mid = left + ((right - left) >> 1);
|
||||
|
||||
if (Compare(pivot, _array[mid], metrics) < 0)
|
||||
{
|
||||
right = mid;
|
||||
}
|
||||
else
|
||||
{
|
||||
left = mid + 1;
|
||||
}
|
||||
}
|
||||
|
||||
logger?.Line($"Вставляем элемент {pivot} на позицию {left}.");
|
||||
|
||||
for (var j = i; j > left; j--)
|
||||
{
|
||||
Assign(_array, j, _array[j - 1], metrics);
|
||||
}
|
||||
|
||||
Assign(_array, left, pivot, metrics);
|
||||
logger?.ArrayState(_array, left);
|
||||
}
|
||||
}
|
||||
|
||||
private void PushRun(int runBase, int runLength)
|
||||
{
|
||||
_runs.Add(new RunInfo(runBase, runLength));
|
||||
}
|
||||
|
||||
private void MergeCollapse()
|
||||
{
|
||||
while (_runs.Count > 1)
|
||||
{
|
||||
var n = _runs.Count - 2;
|
||||
|
||||
if (n > 0 && _runs[n - 1].Length <= _runs[n].Length + _runs[n + 1].Length)
|
||||
{
|
||||
if (_runs[n - 1].Length < _runs[n + 1].Length)
|
||||
{
|
||||
n--;
|
||||
}
|
||||
|
||||
MergeAt(n);
|
||||
}
|
||||
else if (_runs[n].Length <= _runs[n + 1].Length)
|
||||
{
|
||||
MergeAt(n);
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void MergeForceCollapse()
|
||||
{
|
||||
while (_runs.Count > 1)
|
||||
{
|
||||
var n = _runs.Count - 2;
|
||||
|
||||
if (n > 0 && _runs[n - 1].Length < _runs[n + 1].Length)
|
||||
{
|
||||
n--;
|
||||
}
|
||||
|
||||
MergeAt(n);
|
||||
}
|
||||
}
|
||||
|
||||
private void MergeAt(int index)
|
||||
{
|
||||
var metrics = _metrics!;
|
||||
var logger = _logger;
|
||||
|
||||
var base1 = _runs[index].Base;
|
||||
var len1 = _runs[index].Length;
|
||||
var base2 = _runs[index + 1].Base;
|
||||
var len2 = _runs[index + 1].Length;
|
||||
|
||||
logger?.Line(
|
||||
$"Сливаем серии [{base1}; {base1 + len1 - 1}] и [{base2}; {base2 + len2 - 1}].");
|
||||
|
||||
_runs[index] = new RunInfo(base1, len1 + len2);
|
||||
_runs.RemoveAt(index + 1);
|
||||
|
||||
var k = GallopRight(_array[base2], _array, base1, len1, 0, metrics);
|
||||
base1 += k;
|
||||
len1 -= k;
|
||||
|
||||
if (len1 == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
len2 = GallopLeft(_array[base1 + len1 - 1], _array, base2, len2, len2 - 1, metrics);
|
||||
|
||||
if (len2 == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (len1 <= len2)
|
||||
{
|
||||
MergeLo(base1, len1, base2, len2);
|
||||
}
|
||||
else
|
||||
{
|
||||
MergeHi(base1, len1, base2, len2);
|
||||
}
|
||||
|
||||
logger?.ArrayState(_array);
|
||||
}
|
||||
|
||||
private void MergeLo(int base1, int len1, int base2, int len2)
|
||||
{
|
||||
var metrics = _metrics!;
|
||||
|
||||
EnsureCapacity(len1);
|
||||
Array.Copy(_array, base1, _temp, 0, len1);
|
||||
metrics.AddMove(len1);
|
||||
|
||||
var cursor1 = 0;
|
||||
var cursor2 = base2;
|
||||
var dest = base1;
|
||||
|
||||
Assign(_array, dest++, _array[cursor2++], metrics);
|
||||
len2--;
|
||||
|
||||
if (len2 == 0)
|
||||
{
|
||||
Array.Copy(_temp, cursor1, _array, dest, len1);
|
||||
metrics.AddMove(len1);
|
||||
return;
|
||||
}
|
||||
|
||||
if (len1 == 1)
|
||||
{
|
||||
Array.Copy(_array, cursor2, _array, dest, len2);
|
||||
metrics.AddMove(len2);
|
||||
Assign(_array, dest + len2, _temp[cursor1], metrics);
|
||||
return;
|
||||
}
|
||||
|
||||
var minGallop = _minGallop;
|
||||
|
||||
while (true)
|
||||
{
|
||||
var count1 = 0;
|
||||
var count2 = 0;
|
||||
|
||||
do
|
||||
{
|
||||
if (Compare(_array[cursor2], _temp[cursor1], metrics) < 0)
|
||||
{
|
||||
Assign(_array, dest++, _array[cursor2++], metrics);
|
||||
count2++;
|
||||
count1 = 0;
|
||||
len2--;
|
||||
|
||||
if (len2 == 0)
|
||||
{
|
||||
Array.Copy(_temp, cursor1, _array, dest, len1);
|
||||
metrics.AddMove(len1);
|
||||
_minGallop = Math.Max(minGallop, 1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Assign(_array, dest++, _temp[cursor1++], metrics);
|
||||
count1++;
|
||||
count2 = 0;
|
||||
len1--;
|
||||
|
||||
if (len1 == 1)
|
||||
{
|
||||
Array.Copy(_array, cursor2, _array, dest, len2);
|
||||
metrics.AddMove(len2);
|
||||
Assign(_array, dest + len2, _temp[cursor1], metrics);
|
||||
_minGallop = Math.Max(minGallop, 1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
while ((count1 | count2) < minGallop);
|
||||
|
||||
do
|
||||
{
|
||||
count1 = GallopRight(_array[cursor2], _temp, cursor1, len1, 0, metrics);
|
||||
|
||||
if (count1 != 0)
|
||||
{
|
||||
Array.Copy(_temp, cursor1, _array, dest, count1);
|
||||
metrics.AddMove(count1);
|
||||
dest += count1;
|
||||
cursor1 += count1;
|
||||
len1 -= count1;
|
||||
|
||||
if (len1 <= 1)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Assign(_array, dest++, _array[cursor2++], metrics);
|
||||
len2--;
|
||||
|
||||
if (len2 == 0)
|
||||
{
|
||||
Array.Copy(_temp, cursor1, _array, dest, len1);
|
||||
metrics.AddMove(len1);
|
||||
_minGallop = Math.Max(minGallop, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
count2 = GallopLeft(_temp[cursor1], _array, cursor2, len2, 0, metrics);
|
||||
|
||||
if (count2 != 0)
|
||||
{
|
||||
Array.Copy(_array, cursor2, _array, dest, count2);
|
||||
metrics.AddMove(count2);
|
||||
dest += count2;
|
||||
cursor2 += count2;
|
||||
len2 -= count2;
|
||||
|
||||
if (len2 == 0)
|
||||
{
|
||||
Array.Copy(_temp, cursor1, _array, dest, len1);
|
||||
metrics.AddMove(len1);
|
||||
_minGallop = Math.Max(minGallop, 1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Assign(_array, dest++, _temp[cursor1++], metrics);
|
||||
len1--;
|
||||
|
||||
if (len1 == 1)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
minGallop--;
|
||||
}
|
||||
while (count1 >= InitialMinGallop || count2 >= InitialMinGallop);
|
||||
|
||||
if (minGallop < 1)
|
||||
{
|
||||
minGallop = 1;
|
||||
}
|
||||
|
||||
minGallop += 2;
|
||||
|
||||
if (len1 <= 1 || len2 == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
_minGallop = Math.Max(minGallop, 1);
|
||||
|
||||
if (len1 == 1)
|
||||
{
|
||||
Array.Copy(_array, cursor2, _array, dest, len2);
|
||||
metrics.AddMove(len2);
|
||||
Assign(_array, dest + len2, _temp[cursor1], metrics);
|
||||
}
|
||||
else if (len1 > 1)
|
||||
{
|
||||
Array.Copy(_temp, cursor1, _array, dest, len1);
|
||||
metrics.AddMove(len1);
|
||||
}
|
||||
}
|
||||
|
||||
private void MergeHi(int base1, int len1, int base2, int len2)
|
||||
{
|
||||
var metrics = _metrics!;
|
||||
|
||||
EnsureCapacity(len2);
|
||||
Array.Copy(_array, base2, _temp, 0, len2);
|
||||
metrics.AddMove(len2);
|
||||
|
||||
var cursor1 = base1 + len1 - 1;
|
||||
var cursor2 = len2 - 1;
|
||||
var dest = base2 + len2 - 1;
|
||||
|
||||
Assign(_array, dest--, _array[cursor1--], metrics);
|
||||
len1--;
|
||||
|
||||
if (len1 == 0)
|
||||
{
|
||||
Array.Copy(_temp, 0, _array, dest - (len2 - 1), len2);
|
||||
metrics.AddMove(len2);
|
||||
return;
|
||||
}
|
||||
|
||||
if (len2 == 1)
|
||||
{
|
||||
dest -= len1;
|
||||
cursor1 -= len1;
|
||||
Array.Copy(_array, cursor1 + 1, _array, dest + 1, len1);
|
||||
metrics.AddMove(len1);
|
||||
Assign(_array, dest, _temp[cursor2], metrics);
|
||||
return;
|
||||
}
|
||||
|
||||
var minGallop = _minGallop;
|
||||
|
||||
while (true)
|
||||
{
|
||||
var count1 = 0;
|
||||
var count2 = 0;
|
||||
|
||||
do
|
||||
{
|
||||
if (Compare(_temp[cursor2], _array[cursor1], metrics) < 0)
|
||||
{
|
||||
Assign(_array, dest--, _array[cursor1--], metrics);
|
||||
count1++;
|
||||
count2 = 0;
|
||||
len1--;
|
||||
|
||||
if (len1 == 0)
|
||||
{
|
||||
Array.Copy(_temp, 0, _array, dest - (len2 - 1), len2);
|
||||
metrics.AddMove(len2);
|
||||
_minGallop = Math.Max(minGallop, 1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Assign(_array, dest--, _temp[cursor2--], metrics);
|
||||
count2++;
|
||||
count1 = 0;
|
||||
len2--;
|
||||
|
||||
if (len2 == 1)
|
||||
{
|
||||
dest -= len1;
|
||||
cursor1 -= len1;
|
||||
Array.Copy(_array, cursor1 + 1, _array, dest + 1, len1);
|
||||
metrics.AddMove(len1);
|
||||
Assign(_array, dest, _temp[cursor2], metrics);
|
||||
_minGallop = Math.Max(minGallop, 1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
while ((count1 | count2) < minGallop);
|
||||
|
||||
do
|
||||
{
|
||||
count1 = len1 - GallopRight(_temp[cursor2], _array, base1, len1, len1 - 1, metrics);
|
||||
|
||||
if (count1 != 0)
|
||||
{
|
||||
dest -= count1;
|
||||
cursor1 -= count1;
|
||||
len1 -= count1;
|
||||
|
||||
Array.Copy(_array, cursor1 + 1, _array, dest + 1, count1);
|
||||
metrics.AddMove(count1);
|
||||
|
||||
if (len1 == 0)
|
||||
{
|
||||
Array.Copy(_temp, 0, _array, dest - (len2 - 1), len2);
|
||||
metrics.AddMove(len2);
|
||||
_minGallop = Math.Max(minGallop, 1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Assign(_array, dest--, _temp[cursor2--], metrics);
|
||||
len2--;
|
||||
|
||||
if (len2 == 1)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
count2 = len2 - GallopLeft(_array[cursor1], _temp, 0, len2, len2 - 1, metrics);
|
||||
|
||||
if (count2 != 0)
|
||||
{
|
||||
dest -= count2;
|
||||
cursor2 -= count2;
|
||||
len2 -= count2;
|
||||
|
||||
Array.Copy(_temp, cursor2 + 1, _array, dest + 1, count2);
|
||||
metrics.AddMove(count2);
|
||||
|
||||
if (len2 <= 1)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Assign(_array, dest--, _array[cursor1--], metrics);
|
||||
len1--;
|
||||
|
||||
if (len1 == 0)
|
||||
{
|
||||
Array.Copy(_temp, 0, _array, dest - (len2 - 1), len2);
|
||||
metrics.AddMove(len2);
|
||||
_minGallop = Math.Max(minGallop, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
minGallop--;
|
||||
}
|
||||
while (count1 >= InitialMinGallop || count2 >= InitialMinGallop);
|
||||
|
||||
if (minGallop < 1)
|
||||
{
|
||||
minGallop = 1;
|
||||
}
|
||||
|
||||
minGallop += 2;
|
||||
|
||||
if (len1 == 0 || len2 <= 1)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
_minGallop = Math.Max(minGallop, 1);
|
||||
|
||||
if (len2 == 1)
|
||||
{
|
||||
dest -= len1;
|
||||
cursor1 -= len1;
|
||||
Array.Copy(_array, cursor1 + 1, _array, dest + 1, len1);
|
||||
metrics.AddMove(len1);
|
||||
Assign(_array, dest, _temp[cursor2], metrics);
|
||||
}
|
||||
else if (len2 > 1)
|
||||
{
|
||||
Array.Copy(_temp, 0, _array, dest - (len2 - 1), len2);
|
||||
metrics.AddMove(len2);
|
||||
}
|
||||
}
|
||||
|
||||
private void EnsureCapacity(int minCapacity)
|
||||
{
|
||||
if (_temp.Length >= minCapacity)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_temp = new int[minCapacity];
|
||||
}
|
||||
|
||||
private static int GallopLeft(
|
||||
int key,
|
||||
int[] array,
|
||||
int baseIndex,
|
||||
int length,
|
||||
int hint,
|
||||
SortMetrics metrics)
|
||||
{
|
||||
var lastOffset = 0;
|
||||
var offset = 1;
|
||||
|
||||
if (Compare(key, array[baseIndex + hint], metrics) > 0)
|
||||
{
|
||||
var maxOffset = length - hint;
|
||||
|
||||
while (offset < maxOffset && Compare(key, array[baseIndex + hint + offset], metrics) > 0)
|
||||
{
|
||||
lastOffset = offset;
|
||||
offset = (offset << 1) + 1;
|
||||
|
||||
if (offset <= 0)
|
||||
{
|
||||
offset = maxOffset;
|
||||
}
|
||||
}
|
||||
|
||||
if (offset > maxOffset)
|
||||
{
|
||||
offset = maxOffset;
|
||||
}
|
||||
|
||||
lastOffset += hint;
|
||||
offset += hint;
|
||||
}
|
||||
else
|
||||
{
|
||||
var maxOffset = hint + 1;
|
||||
|
||||
while (offset < maxOffset && Compare(key, array[baseIndex + hint - offset], metrics) <= 0)
|
||||
{
|
||||
lastOffset = offset;
|
||||
offset = (offset << 1) + 1;
|
||||
|
||||
if (offset <= 0)
|
||||
{
|
||||
offset = maxOffset;
|
||||
}
|
||||
}
|
||||
|
||||
if (offset > maxOffset)
|
||||
{
|
||||
offset = maxOffset;
|
||||
}
|
||||
|
||||
var temp = lastOffset;
|
||||
lastOffset = hint - offset;
|
||||
offset = hint - temp;
|
||||
}
|
||||
|
||||
lastOffset++;
|
||||
|
||||
while (lastOffset < offset)
|
||||
{
|
||||
var middle = lastOffset + ((offset - lastOffset) >> 1);
|
||||
|
||||
if (Compare(key, array[baseIndex + middle], metrics) > 0)
|
||||
{
|
||||
lastOffset = middle + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
offset = middle;
|
||||
}
|
||||
}
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
private static int GallopRight(
|
||||
int key,
|
||||
int[] array,
|
||||
int baseIndex,
|
||||
int length,
|
||||
int hint,
|
||||
SortMetrics metrics)
|
||||
{
|
||||
var offset = 1;
|
||||
var lastOffset = 0;
|
||||
|
||||
if (Compare(key, array[baseIndex + hint], metrics) < 0)
|
||||
{
|
||||
var maxOffset = hint + 1;
|
||||
|
||||
while (offset < maxOffset && Compare(key, array[baseIndex + hint - offset], metrics) < 0)
|
||||
{
|
||||
lastOffset = offset;
|
||||
offset = (offset << 1) + 1;
|
||||
|
||||
if (offset <= 0)
|
||||
{
|
||||
offset = maxOffset;
|
||||
}
|
||||
}
|
||||
|
||||
if (offset > maxOffset)
|
||||
{
|
||||
offset = maxOffset;
|
||||
}
|
||||
|
||||
var temp = lastOffset;
|
||||
lastOffset = hint - offset;
|
||||
offset = hint - temp;
|
||||
}
|
||||
else
|
||||
{
|
||||
var maxOffset = length - hint;
|
||||
|
||||
while (offset < maxOffset && Compare(key, array[baseIndex + hint + offset], metrics) >= 0)
|
||||
{
|
||||
lastOffset = offset;
|
||||
offset = (offset << 1) + 1;
|
||||
|
||||
if (offset <= 0)
|
||||
{
|
||||
offset = maxOffset;
|
||||
}
|
||||
}
|
||||
|
||||
if (offset > maxOffset)
|
||||
{
|
||||
offset = maxOffset;
|
||||
}
|
||||
|
||||
lastOffset += hint;
|
||||
offset += hint;
|
||||
}
|
||||
|
||||
lastOffset++;
|
||||
|
||||
while (lastOffset < offset)
|
||||
{
|
||||
var middle = lastOffset + ((offset - lastOffset) >> 1);
|
||||
|
||||
if (Compare(key, array[baseIndex + middle], metrics) < 0)
|
||||
{
|
||||
offset = middle;
|
||||
}
|
||||
else
|
||||
{
|
||||
lastOffset = middle + 1;
|
||||
}
|
||||
}
|
||||
|
||||
return offset;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user