很久没有玩算法了,都快忘记了,手写复习下,同时发现了git上很多错误,进行了改进。
namespace Test
{
/// <summary>
/// 排序算法类
/// </summary>
/// <typeparam name="T"></typeparam>
public static class SortedUtil<T> where T:IComparable<T>
{
/// <summary>
/// 选择排序
/// 思想是从索引为i=0开始,依次选择数组中([i~length-1])最小的元素与第i个元素交换位置
/// </summary>
/// <param name="origionArray"></param>
/// <returns></returns>
public static T[] SelectionSort(T[] origionArray)
{
for (int i = 0; i <= origionArray.Length-2; i++)
{
int swapIndex = i;
int j=i+1;
while (j <= origionArray.Length-1)
{
if(origionArray[j].CompareTo(origionArray[swapIndex]) < 0)
{
swapIndex = j;
}
j++;
}
T data=origionArray[i];
origionArray[i] = origionArray[swapIndex];
origionArray[swapIndex] = data;
}
return origionArray;
}
/// <summary>
/// 插入排序
/// 思想是有两手牌,一手牌是排序好的(初始只有一张牌),一手是无序的,每次从无序的牌中抽出一张放入排序好的牌中,保证顺序。重复此步骤直到所有牌排序完成
/// </summary>
/// <param name="origionArray"></param>
/// <returns></returns>
public static T[] InsertionSort(T[] origionArray)
{
for (int i = 1; i < origionArray.Length; i++)
{
int j = i - 1;
T data = origionArray[i];
while (j >= 0 && origionArray[j].CompareTo(data) > 0)
{
origionArray[j+1] =origionArray[j];
j--;
}
origionArray[j + 1] = data;
}
return origionArray;
}
/// <summary>
/// 归并排序
/// 思想是把排序看作一个递归的过程,把两个排序好的子序列合成一个排序好的子序列。
/// </summary>
/// <param name="origionArray"></param>
/// <param name="p"></param>
/// <param name="r"></param>
public static void MergeSort(T[] origionArray,int p,int r)
{
if (p < r)
{
int q = (r + p) / 2;
MergeSort(origionArray,p,q);
MergeSort(origionArray,q+1,r);
Merge(origionArray,p,q,r);
}
}
/// <summary>
/// 归并排序的归并过程(把两个排序好的子序列合成一个排序好的子序列。)
/// </summary>
/// <param name="origionArray"></param>
/// <param name="p"></param>
/// <param name="q"></param>
/// <param name="r"></param>
public static void Merge(T[] origionArray,int p,int q,int r)
{
T[] copyOne = new T[q - p + 1];
T[] copyTwo=new T[r - q];
for (int s = 0; s < q - p + 1; s++)
{
copyOne[s] = origionArray[p + s];
}
for (int s = 0; s < r-q; s++)
{
copyTwo[s] = origionArray[q + s + 1];
}
int a=0, b = 0;
int i = p;
for (; i <= r; i++)
{
if (a >= copyOne.Length || b >= copyTwo.Length)
break;
if (copyOne[a].CompareTo(copyTwo[b]) < 0)
{
origionArray[i] = copyOne[a++];
}
else
{
origionArray[i] = copyTwo[b++];
}
}
if (i <= r)
{
if (a >= copyOne.Length)
{
for (; i <= r; i++)
{
origionArray[i] = copyTwo[b++];
}
}
else if (b >= copyTwo.Length)
{
for (; i <= r; i++)
{
origionArray[i] = copyOne[a++];
}
}
}
}
/// <summary>
/// 快速排序
/// 思想是在数组中选取一个元素进行拆分,左边的元素都比这个元素小,右边的元素都比这个元素大。重复这个过程直到元素有序
/// </summary>
/// <param name="origionArray"></param>
/// <param name="p"></param>
/// <param name="r"></param>
public static void QuickSort(T[] origionArray,int p,int r)
{
if (p < r)
{
int q = Partion(origionArray,p,r);
QuickSort(origionArray,p,q-1);
QuickSort(origionArray,q+1,r);
}
}
/// <summary>
/// 快排拆分过程
/// </summary>
/// <param name="origionArray"></param>
/// <param name="p"></param>
/// <param name="r"></param>
/// <returns></returns>
public static int Partion(T[] origionArray,int p,int r)
{
var key = origionArray[r];
int i = p - 1;
for (int j = p; j < r; j++)
{
if(origionArray[j].CompareTo(key)<0)
{
T data = origionArray[++i];
origionArray[i] = origionArray[j];
origionArray[j] = data;
}
}
T current = origionArray[i + 1];
origionArray[i + 1] = origionArray[r];
origionArray[r] = current;
return i + 1;
}
/// <summary>
/// 冒泡排序
/// 思想是每次都把最大的一块石头沉底(或者把最轻的浮起来)
/// </summary>
/// <param name="origionArray"></param>
public static void BubbleSort(T[] origionArray)
{
for (int i = 0; i < origionArray.Length-1; i++)
{
for (int j = 1; j < origionArray.Length-i; j++)
{
if (origionArray[j].CompareTo(origionArray[j - 1]) < 0)
{
T data = origionArray[j];
origionArray[j] = origionArray[j - 1];
origionArray[j - 1] = data;
}
}
}
}
/// <summary>
/// 堆排序
/// 利用最大堆或者最小堆的堆顶元素是最大或最小,依次取出堆顶元素,维护堆性质并且缩容,达到排序目的
/// </summary>
/// <param name="origionArray"></param>
/// <returns></returns>
public static T[] HeapSort(T[] origionArray)
{
return new Heap(origionArray).HeapSort();
}
/// <summary>
/// 计数排序
/// 思想是统计每个元素的个数逐次累加就可以得出这个元素在数组中的位置
/// 这里为了支持泛型的元素,使用了底层是二叉搜索树的SortedDictionary结构,一般使用List数组即可
/// </summary>
/// <param name="origionArray"></param>
/// <returns></returns>
public static T[] CountingSort(T[] origionArray)
{
SortedDictionary<T,int> keyValuePairs= new SortedDictionary<T, int>();
foreach (var item in origionArray)
{
if (keyValuePairs.ContainsKey(item))
keyValuePairs[item]++;
else
keyValuePairs.Add(item,1);
}
for (int i = 0; i < keyValuePairs.Count-1; i++)
{
T key =keyValuePairs.Keys.ToList()[i];
T keyNext = keyValuePairs.Keys.ToList()[i + 1];
keyValuePairs[keyNext] += keyValuePairs[key];
}
T[] sortedArray = new T[origionArray.Length];
foreach (var item in origionArray)
{
sortedArray[--keyValuePairs[item]] = item;
}
return sortedArray;
}
/// <summary>
/// 基数排序
/// 本质是一种桶排序,先分配,后收集。它的分桶是通过位来实现的。从低位到高位(从高到低也可,只是需要分子桶),每一位分配后收集,重复直到最高位,最后达到有序
/// </summary>
/// <param name="origionArray"></param>
public static void RadixSort(int[] origionArray)
{
List<int>[] buket = new List<int>[10];
for (int i = 0; i < 10; i++)
{
buket[i] = new List<int>();
}
int maxPosition = MaxPosition(origionArray);
for (int i = 0; i < maxPosition; i++)
{
for (int j = 0; j < origionArray.Length; j++)
{
int current = origionArray[j];
int currentPosition = current.ToString().Length < i + 1 ? 0 : int.Parse(current.ToString()[current.ToString().Length - i - 1].ToString());
buket[currentPosition].Add(current);
}
int index = 0;
for (int k = 0; k < 10; k++)
{
foreach (var item in buket[k])
{
origionArray[index++] = item;
}
buket[k]=new List<int>();
}
}
}
/// <summary>
/// 桶排序(按照一定规则分桶,然后对每个桶进行插入排序,再收集就是排序好的序列)
/// 其实分桶的大小无所谓,最好均匀分布,比如你可以把20-70的数分到一个桶子里
/// </summary>
/// <param name="origionArray"></param>
public static void BuketSort(int[] origionArray)
{
int buketCount = SplitBuket(origionArray,10);
List<int>[] buket = new List<int>[buketCount];
for (int i = 0; i < buket.Length; i++)
{
buket[i] = new List<int>();
}
for (int i = 0; i < origionArray.Length; i++)
{
int current = origionArray[i];
int buketIndex = (current - origionArray.Min()) / 10;
buket[buketIndex].Add(current);
}
for (int i = 0; i < buket.Length; i++)
{
int[] currentBuket = buket[i].ToArray();
buket[i]= SortedUtil<int>.InsertionSort(currentBuket).ToList();
}
int index = 0;
for (int i = 0; i < buket.Length; i++)
{
for (int j = 0; j < buket[i].Count; j++)
{
origionArray[index++] = buket[i][j];
}
}
}
/// <summary>
/// 希尔排序(间隔插入排序,先使用较大的间隔插入排序使得元素基本有序,再逐渐缩小间隔,最后整体再进行一次插入排序,使得元素有序)
/// </summary>
/// <param name="origionArray"></param>
public static void ShellSort(T[] origionArray)
{
int distance = 1,j;
while (distance<origionArray.Length/3)
{
distance = distance * 3 + 1;
}
for (; distance >0; distance/=3)
{
for (int i = distance; i<origionArray.Length; i++)
{
T temp = origionArray[i];
for (j =i- distance; j >=0 && origionArray[j].CompareTo(temp)>0; j-=distance)
{
origionArray[j + distance] = origionArray[j];
}
origionArray[j + distance] = temp;
}
}
}
#region Helpers
public static string ToString(T[] array)
{
string s = string.Empty;
for (int i = 0; i < array.Length; i++)
{
s += $"-> {array[i]}";
}
return s;
}
/// <summary>
/// 分桶
/// </summary>
/// <param name="origionArray"></param>
/// <param name="distance"></param>
/// <returns></returns>
public static int SplitBuket(int[] origionArray,int distance=10)
{
int min = origionArray.Min();
int max = origionArray.Max();
int buketCount = (max - min) / distance;
if (buketCount * distance < max) buketCount += 1;
return buketCount;
}
/// <summary>
/// 最大位
/// </summary>
/// <param name="origionArray"></param>
/// <returns></returns>
public static int MaxPosition(int[] origionArray)
{
return origionArray.ToList().Max(t=>t.ToString().Length);
}
/// <summary>
/// 最小堆
/// </summary>
public class Heap
{
private T[] _data;
public int HeapSize { get; private set; }
public Heap(T[] origionArray)
{
_data = origionArray;
BuildHeap();
}
/// <summary>
/// 堆排序
/// </summary>
/// <returns></returns>
public T[] HeapSort()
{
int index = HeapSize - 1;
for (int i = index; i > 0; i--)
{
T data = _data[0];
_data[0] = _data[i];
_data[i] = data;
HeapSize--;
MaintainHeap(0);
}
return _data;
}
/// <summary>
/// 建立堆
/// </summary>
private void BuildHeap()
{
HeapSize = _data.Length;
int index = _data.Length / 2;
for (int i = index - 1; i >= 0; i--)
{
MaintainHeap(i);
}
}
/// <summary>
/// 维护堆的性质
/// </summary>
/// <param name="index"></param>
private void MaintainHeap(int index)
{
int maxIndex = index;
if (Left(index) < HeapSize && _data[maxIndex].CompareTo(_data[Left(index)]) < 0)
{
maxIndex = Left(index);
}
if (Right(index) < HeapSize && _data[maxIndex].CompareTo(_data[Right(index)]) < 0)
{
maxIndex = Right(index);
}
if (index != maxIndex)
{
T data = _data[index];
_data[index] = _data[maxIndex];
_data[maxIndex] = data;
MaintainHeap(maxIndex);
}
}
private int Left(int index)
{
return index * 2 + 1;
}
private int Right(int index)
{
return index * 2 + 2;
}
}
#endregion
}
}
测试:
int[] array = new int[] { 1, 15, 24, 65, 98, 63, 45, 5, 3 };
//var sortedArray = SortedUtil<int>.SelectionSort(array);
var sortedArray = SortedUtil<int>.InsertionSort(array);
Console.WriteLine(SortedUtil<int>.ToString(sortedArray));
int[] mergeArray = new int[] { 2, 4, 6, 1, 3, 5 };
SortedUtil<int>.MergeSort(mergeArray, 0, 5);
Console.WriteLine(SortedUtil<int>.ToString(mergeArray));
int[] quickArray = new int[] { 15, 65, 48, 54, 33, 2, 9, 22, 13 };
SortedUtil<int>.QuickSort(quickArray, 0, 8);
Console.WriteLine(SortedUtil<int>.ToString(quickArray));
int[] bubbleSortArr = new int[] { 15, 65, 48, 54, 33, 2, 9, 22, 13 };
SortedUtil<int>.BubbleSort(bubbleSortArr);
Console.WriteLine(SortedUtil<int>.ToString(bubbleSortArr));
int[] heapSortArr = new int[] { 15, 65, 48, 54, 33, 2, 9, 22, 13 };
Console.WriteLine(SortedUtil<int>.ToString(SortedUtil<int>.HeapSort(heapSortArr)));
int[] countingSortArr = new int[] { 15, 65, 48, 54, 33, 2, 9, 22, 13 };
Console.WriteLine(SortedUtil<int>.ToString(SortedUtil<int>.CountingSort(countingSortArr)));
int[] radixSortArr = new int[] { 156, 6548, 48, 546, 33, 2, 9, 22, 13 };
SortedUtil<int>.RadixSort(radixSortArr);
Console.WriteLine(SortedUtil<int>.ToString(radixSortArr));
int[] buketSortArr = new int[] { 15, 65, 48, 54, 33, 2, 9, 22, 13 };
SortedUtil<int>.BuketSort(buketSortArr);
Console.WriteLine(SortedUtil<int>.ToString(buketSortArr));
int[] shellSortArr = new int[] { 15, 65, 48, 54, 33, 2, 9, 22, 13 };
SortedUtil<int>.ShellSort(shellSortArr);
Console.WriteLine(SortedUtil<int>.ToString(shellSortArr));
结果如下
github:https://github.com/pw8992134/Algorithm/blob/master/Algorithm/Sort/SortUtil.cs