277 lines
6.7 KiB
C#
277 lines
6.7 KiB
C#
using System.Collections.Generic;
|
|
|
|
namespace InternalSortMethods.Models;
|
|
|
|
public abstract class SortingAlgorithm
|
|
{
|
|
public abstract string Name { get; }
|
|
public abstract string NameRu { get; }
|
|
|
|
protected List<SortStep> Steps { get; } = [];
|
|
protected int[] _array = [];
|
|
|
|
public SortingResult Sort(int[] array)
|
|
{
|
|
_array = (int[])array.Clone();
|
|
Steps.Clear();
|
|
OnSort();
|
|
return new SortingResult
|
|
{
|
|
SortedArray = _array,
|
|
Steps = [.. Steps]
|
|
};
|
|
}
|
|
|
|
protected void Compare(int i, int j)
|
|
{
|
|
Steps.Add(new SortStep(i, j, SortActionType.Compare));
|
|
}
|
|
|
|
protected void Swap(int i, int j)
|
|
{
|
|
(_array[i], _array[j]) = (_array[j], _array[i]);
|
|
Steps.Add(new SortStep(i, j, SortActionType.Swap, (int[])_array.Clone()));
|
|
}
|
|
|
|
protected void SetValue(int index, int value)
|
|
{
|
|
_array[index] = value;
|
|
Steps.Add(new SortStep(index, -1, SortActionType.Set, (int[])_array.Clone()));
|
|
}
|
|
|
|
protected void MarkSorted(int index)
|
|
{
|
|
Steps.Add(new SortStep(index, -1, SortActionType.MarkSorted));
|
|
}
|
|
|
|
protected void MarkPivot(int index)
|
|
{
|
|
Steps.Add(new SortStep(index, -1, SortActionType.MarkPivot));
|
|
}
|
|
|
|
protected abstract void OnSort();
|
|
}
|
|
|
|
public class BubbleSort : SortingAlgorithm
|
|
{
|
|
public override string Name => "Bubble Sort";
|
|
public override string NameRu => "Пузырьковая";
|
|
|
|
protected override void OnSort()
|
|
{
|
|
int n = _array.Length;
|
|
for (int i = 0; i < n - 1; i++)
|
|
{
|
|
bool swapped = false;
|
|
for (int j = 0; j < n - i - 1; j++)
|
|
{
|
|
Compare(j, j + 1);
|
|
if (_array[j] > _array[j + 1])
|
|
{
|
|
Swap(j, j + 1);
|
|
swapped = true;
|
|
}
|
|
}
|
|
MarkSorted(n - i - 1);
|
|
if (!swapped) break;
|
|
}
|
|
MarkSorted(0);
|
|
}
|
|
}
|
|
|
|
public class SelectionSort : SortingAlgorithm
|
|
{
|
|
public override string Name => "Selection Sort";
|
|
public override string NameRu => "Выбором";
|
|
|
|
protected override void OnSort()
|
|
{
|
|
int n = _array.Length;
|
|
for (int i = 0; i < n - 1; i++)
|
|
{
|
|
int minIdx = i;
|
|
for (int j = i + 1; j < n; j++)
|
|
{
|
|
Compare(j, minIdx);
|
|
if (_array[j] < _array[minIdx])
|
|
minIdx = j;
|
|
}
|
|
if (minIdx != i)
|
|
Swap(i, minIdx);
|
|
MarkSorted(i);
|
|
}
|
|
MarkSorted(n - 1);
|
|
}
|
|
}
|
|
|
|
public class InsertionSort : SortingAlgorithm
|
|
{
|
|
public override string Name => "Insertion Sort";
|
|
public override string NameRu => "Вставками";
|
|
|
|
protected override void OnSort()
|
|
{
|
|
int n = _array.Length;
|
|
for (int i = 1; i < n; i++)
|
|
{
|
|
int key = _array[i];
|
|
int j = i - 1;
|
|
Compare(j, i);
|
|
while (j >= 0 && _array[j] > key)
|
|
{
|
|
SetValue(j + 1, _array[j]);
|
|
j--;
|
|
if (j >= 0) Compare(j, i);
|
|
}
|
|
SetValue(j + 1, key);
|
|
}
|
|
MarkSorted(0);
|
|
}
|
|
}
|
|
|
|
public class QuickSort : SortingAlgorithm
|
|
{
|
|
public override string Name => "Quick Sort";
|
|
public override string NameRu => "Быстрая";
|
|
|
|
protected override void OnSort()
|
|
{
|
|
QuickSortRecursive(0, _array.Length - 1);
|
|
MarkSorted(0);
|
|
}
|
|
|
|
private void QuickSortRecursive(int low, int high)
|
|
{
|
|
if (low < high)
|
|
{
|
|
int pi = Partition(low, high);
|
|
QuickSortRecursive(low, pi - 1);
|
|
QuickSortRecursive(pi + 1, high);
|
|
}
|
|
}
|
|
|
|
private int Partition(int low, int high)
|
|
{
|
|
int pivot = _array[high];
|
|
MarkPivot(high);
|
|
int i = low - 1;
|
|
for (int j = low; j < high; j++)
|
|
{
|
|
Compare(j, high);
|
|
if (_array[j] < pivot)
|
|
{
|
|
i++;
|
|
if (i != j) Swap(i, j);
|
|
}
|
|
}
|
|
if (i + 1 != high) Swap(i + 1, high);
|
|
MarkSorted(i + 1);
|
|
return i + 1;
|
|
}
|
|
}
|
|
|
|
public class MergeSort : SortingAlgorithm
|
|
{
|
|
public override string Name => "Merge Sort";
|
|
public override string NameRu => "Слиянием";
|
|
|
|
protected override void OnSort()
|
|
{
|
|
MergeSortRecursive(0, _array.Length - 1);
|
|
MarkSorted(0);
|
|
}
|
|
|
|
private void MergeSortRecursive(int left, int right)
|
|
{
|
|
if (left < right)
|
|
{
|
|
int mid = left + (right - left) / 2;
|
|
MergeSortRecursive(left, mid);
|
|
MergeSortRecursive(mid + 1, right);
|
|
Merge(left, mid, right);
|
|
}
|
|
}
|
|
|
|
private void Merge(int left, int mid, int right)
|
|
{
|
|
int n1 = mid - left + 1;
|
|
int n2 = right - mid;
|
|
int[] leftArr = new int[n1];
|
|
int[] rightArr = new int[n2];
|
|
|
|
for (int x = 0; x < n1; x++) leftArr[x] = _array[left + x];
|
|
for (int x = 0; x < n2; x++) rightArr[x] = _array[mid + 1 + x];
|
|
|
|
int i = 0, j = 0, k = left;
|
|
while (i < n1 && j < n2)
|
|
{
|
|
Compare(left + i, mid + 1 + j);
|
|
if (leftArr[i] <= rightArr[j])
|
|
{
|
|
SetValue(k, leftArr[i]);
|
|
i++;
|
|
}
|
|
else
|
|
{
|
|
SetValue(k, rightArr[j]);
|
|
j++;
|
|
}
|
|
k++;
|
|
}
|
|
while (i < n1)
|
|
{
|
|
SetValue(k, leftArr[i]);
|
|
i++; k++;
|
|
}
|
|
while (j < n2)
|
|
{
|
|
SetValue(k, rightArr[j]);
|
|
j++; k++;
|
|
}
|
|
}
|
|
}
|
|
|
|
public class HeapSort : SortingAlgorithm
|
|
{
|
|
public override string Name => "Heap Sort";
|
|
public override string NameRu => "Кучей";
|
|
|
|
protected override void OnSort()
|
|
{
|
|
int n = _array.Length;
|
|
for (int i = n / 2 - 1; i >= 0; i--)
|
|
Heapify(n, i);
|
|
for (int i = n - 1; i > 0; i--)
|
|
{
|
|
Swap(0, i);
|
|
MarkSorted(i);
|
|
Heapify(i, 0);
|
|
}
|
|
MarkSorted(0);
|
|
}
|
|
|
|
private void Heapify(int heapSize, int root)
|
|
{
|
|
int largest = root;
|
|
int left = 2 * root + 1;
|
|
int right = 2 * root + 2;
|
|
|
|
if (left < heapSize)
|
|
{
|
|
Compare(left, largest);
|
|
if (_array[left] > _array[largest])
|
|
largest = left;
|
|
}
|
|
if (right < heapSize)
|
|
{
|
|
Compare(right, largest);
|
|
if (_array[right] > _array[largest])
|
|
largest = right;
|
|
}
|
|
if (largest != root)
|
|
{
|
|
Swap(root, largest);
|
|
Heapify(heapSize, largest);
|
|
}
|
|
}
|
|
} |