概述
十大经典排序算法分别是冒泡排序、插入排序、选择排序、希尔排序、计数排序、基数排序、桶排序、快速排序、归并排序和堆排序。
可以分为两大类:
比较类排序:通过比较来决定元素间的相对次序,由于其时间复杂度不能突破O(nlogn),因此也称为非线性时间比较类排序。
非比较类排序:不通过比较来决定元素间的相对次序,它可以突破基于比较排序的时间下界,以线性时间运行,因此也称为线性时间非比较类排序。
冒泡排序
(Bubble Sort)
是一种交换排序,通过两两比较相邻记录的关键字,如果反序则交换,直到没有反序的记录为止。
C#实现
public static void Swap(ref int num1,ref int num2)
{
int temp = num1;
num1 = num2;
num2 = temp;
}
//从小到大排序
public static void BubbleSort(int[] array)
{
//循环判断的趟数 进行N-1趟排序
for (int i = 1; i < array.Length; i++)
{
bool canSwap = false;
//从第一个元素进行遍历比对,如果前一个元素大于后一个元素,就进行交换
for(int j = 0;j< array.Length-i; j++)
{
if (array[j] > array[j + 1])
{
Swap(ref array[j], ref array[j + 1]);
canSwap = true;
}
}
//判断元素比较时是否有交换操作,如果没有则说明序列已排序,跳出循环
if(!canSwap)
{
break;
}
}
}
Lua实现
local Print = function(list)
local str = ""
for k,v in ipairs(list)do
str = str..v.." "
end
print(str)
end
function BubbleSort(arr)
--判断的趟数 (n-1次)
for i = 1,#arr-1 do
--判断在一趟排序中是否有进行过交换操作
local isSwap = false
--在改趟排序中进行比较
for j = 1,#arr-i do
print(j)
if arr[j] > arr[j+1] then
arr[j],arr[j+1] = arr[j+1],arr[j]
isSwap = true
end
end
--如果没有进行交换操作,说明已排好序
if not isSwap then
break
end
end
end
local numList = { 10, 8, 11, 7, 4, 12, 9, 6, 5, 3 ,0,2,1,2};
BubbleSort(numList)
Print(numList)
简单选择排序
(Simple Selection Sort)
1、对长度为n的序列进行n-1趟排序,每次从待排序列中选出最小的元素,并与待排序列中的第一个元素交换
2、不稳定排序
C#实现
public void SimpleSelectionSort(int[] arr)
{
int minIndex;//待排序列中最小值索引
int i, j;
//从第一个值开始到倒数第二个数,从该值之后的序列中找出最小值
for (i = 0; i < arr.Length - 1; i++)
{
//将待排序列的第一个值的索引暂定为最小值索引
minIndex = i;
for (j = i+1; j < arr.Length; j++)
{
//从待排序列中找出最小值索引
if (arr[j] < arr[minIndex])
{
minIndex = j;
}
}
if (minIndex != i)
{
//将最小值与待排序列的第一个值进行交换
(arr[minIndex], arr[i]) = (arr[i], arr[minIndex]);
}
}
}
Lua实现
local Print = function(list)
local str = ""
for k,v in ipairs(list)do
str = str..v.." "
end
print(str)
end
--简单选择排序
function SimpleSelectionSort(arr)
local minIndex;--最小值索引
--从第一个值开始到倒数二个数,从该数之后的序列中找出最小值
for i = 1,#arr-1 do
minIndex = i
for j = i+1,#arr do
if arr[j] < arr[minIndex] then
minIndex = j
end
end
if minIndex ~= i then
--将最小值与待排序列中的第一个数进行交换
arr[i],arr[minIndex] = arr[minIndex],arr[i]
end
end
end
local numList = { 10, 8, 11, 7, 4, 12, 9, 6, 5, 3 ,0,2,1,2};
SampleSelectionSort(numList)
Print(numList)
直接插入排序
(Straight Insertion Sort)
将一个记录插入到已经排好序的有序表中,从而得到一个新的、记录数增1的有序表。
C#实现
public static void PrintList(int[] array)
{
for (int i =0;i<array.Length; i++)
{
Console.Write(array[i]+" ");
}
Console.WriteLine("\n");
}
public static void Swap(ref int num1,ref int num2)
{
int temp = num1;
num1 = num2;
num2 = temp;
}
public static void StraightInsertSort(int[] array)
{
for(int i = 1;i< array.Length; i++)
{
int key = array[i];
int j = i - 1;
while (j >= 0 && array[j] > key)
{
array[j + 1] = array[j];
j--;
}
array[j + 1] = key;
}
}
Lua实现
--直接插入排序
local SampleInsertSort = function(list)
for i = 2,#list do
local key = list[i]
local j = i-1
while(j>=1 and list[j] > key) do
list[j+1] = list[j]
j = j - 1
end
list[j+1] = key
end
end
local numList = { 10, 8, 11, 7, 4, 12, 9, 6, 5, 3 ,0,2,1,2};
SampleInsertSort(numList)
Print(numList)
希尔排序
(Shell Sort)
又称缩小增量排序,设定一个增量,将序列中的记录通过该增量进行分组,在组内进行直接插入排序。不断缩小增量,直到最后进行一次增量为1的直接插入排序。
C#实现
public void ShellSort(int[] arr)
{
//计算出所有增量情况
for (int step = arr.Length / 2; step >= 1; step /= 2)
{
//处理各增量的分组
for (int group = 0; group < step; group++)
{
//对该分组进行直接插入排序
for (int i = group + step; i < arr.Length; i += step)
{
int value = arr[i];
int j = i - step;
while (j >= 0 && arr[j] > value)
{
arr[j+step] = arr[j];
j -= step;
}
arr[j + step] = value;
}
}
}
}
Lua实现
function ShellSort(arr)
--计算所有增量情况
local step = math.modf(#arr/2)
while(step >=1)do
--根据增量进行分组
for group = 1,step do
--对当组进行直接插入排序
for i = group+step,#arr,step do
local value = arr[i]
local j = i-step
while(j >=1 and arr[j] > value) do
arr[j+step] = arr[j]
j = j - step
end
arr[j+step] = value
end
end
step = math.modf(step/2)
end
end
快速排序
(Quick Sort)
在待排序列中设定一个中心点pivot,将小于中心点的元素放到pivot的左边,大于中心点的元素放在Pivot的右边,然后通过递归对左右两个序列进行上述操作。
C#实现
public static void PrintList(int[] array)
{
for (int i =0;i<array.Length; i++)
{
Console.Write(array[i]+" ");
}
Console.WriteLine("\n");
}
public void QuickSort(int[] arr)
{
QSort(arr,0,arr.Length-1);
}
private void QSort(int[] arr, int low, int high)
{
if (low < high)
{
int pivot = GetPivot(arr, low, high);
QSort(arr,low,pivot-1);
QSort(arr,pivot+1,high);
}
}
private int GetPivot(int[] arr, int low, int high)
{
int pivotkey = arr[low];
while (low < high)
{
while (low < high && arr[high] >= pivotkey)
{
high--;
}
(arr[high], arr[low]) = (arr[low], arr[high]);
while (low < high && arr[low] <= pivotkey)
{
low++;
}
(arr[high], arr[low]) = (arr[low], arr[high]);
}
return low;
}
int[] numList = { 10, 8, 11, 7, 4, 12, 9, 6, 5, 3 ,0,2,1,23};
Sort.QuickSort(numList);
Sort.PrintList(numList);
Lua实现
function QuickSort(arr)
__QSort(arr,1,#arr)
end
function __QSort(arr,low,high)
if low < high then
local pivot = __GetPivot(arr,low,high)
__QSort(arr,low,pivot-1)
__QSort(arr,pivot+1,high)
end
end
function __GetPivot(arr,low,high)
local pivotKey = arr[low]
while(low<high)do
while(low<high and arr[high] >= pivotKey)do
high = high-1
end
arr[low],arr[high] = arr[high],arr[low]
while(low<high and arr[low] <= pivotKey) do
low = low+1
end
arr[low],arr[high] = arr[high],arr[low]
end
return low
end
local numList = { 10, 8, 11, 7, 4, 12, 9, 6, 5, 3 ,0,2,1,2};
QuickSort(numList)
Print(numList)
堆排序
(Heap Sort)
将数组初始化为一个大顶堆;进行n-1趟操作,每趟操作堆顶元素与待排末尾元素交换,然后从堆顶开始将剩余元素重新调整为一个大顶堆。
C#实现
/// <summary>
/// 堆排序
/// </summary>
/// <param name="arr"></param>
public static void HeapSort(int[] arr)
{
//将序列初始化为一个大顶堆
for(int i = arr.Length / 2 - 1; i >= 0; i--)
{
HeapAdjust(arr, arr.Length, i);
}
//依次取出堆顶元素,并重新调整堆
for (int i = arr.Length - 1; i >= 1; i--)
{
//将堆顶元素与当前最后一个元素交换
(arr[0], arr[i]) = (arr[i], arr[0]);
//重新调整堆
HeapAdjust(arr, i, 0);
}
}
//调整序列为一个大顶堆
public static void HeapAdjust(int[] arr,int length,int index)
{
int heapIndex = index;
int leftIndex = index * 2 + 1;//左子节点索引
int rightIndex = index * 2 + 2;//右子节点索引
//如果左子节点大于父节点,则更新最大值
if (leftIndex < length && arr[leftIndex] > arr[heapIndex])
{
heapIndex = leftIndex;
}
//如果右子节点大于父节点和左子节点,则更新最大值
if (rightIndex < length && arr[rightIndex] > arr[heapIndex])
{
heapIndex = rightIndex;
}
//如果最大值不是当前父节点,则交换父节点和最大值,并继续向下调整堆
if (heapIndex != index)
{
(arr[heapIndex], arr[index]) = (arr[index], arr[heapIndex]);
HeapAdjust(arr, length, heapIndex);
}
}
Lua实现
function HeapSort(arr)
--将序列初始化为一个大顶堆
for i=(math.modf(#arr/2)),1,-1 do
HeapAdjust(arr,#arr,i)
end
for i = #arr,2,-1 do
arr[1],arr[i] = arr[i],arr[1]
HeapAdjust(arr,i-1,1)
end
end
--将序列调整为大顶堆
function HeapAdjust(arr,length,index)
local heapIndex = index
--左子节点的索引
local leftIndex = index*2
--右子节点的索引
local rightIndex = index*2+1
--如果左子节点大于父节点,则更新最大值
if leftIndex <= length and arr[leftIndex] > arr[heapIndex] then
heapIndex = leftIndex
end
--如果右子节点大于父节点和左子节点,则更新最大值
if rightIndex <= length and arr[rightIndex] > arr[heapIndex] then
heapIndex = rightIndex
end
--如果最大值不是当前父节点,则交换父节点和最大值,并继续向下调整堆
if heapIndex ~= index then
arr[heapIndex],arr[index] = arr[index],arr[heapIndex]
HeapAdjust(arr,length,heapIndex)
end
end
归并排序
(Merge Sort)
归并排序可以分为两个主要步骤:分解和合并。在分解步骤中,序列被不断地分解成更小的子序列,直到子序列的大小为1。在合并步骤中,这些已经排序的子序列被逐步合并,直到合并成一个完整的、有序的序列。
C#实现
void MergeSort(int[] arr)
{
int[] tempArr = new int[arr.Length];
Merge_Sort(arr, 0, arr.Length - 1, tempArr);
}
void Merge_Sort(int[] arr,int low,int high,int[] tempArr)
{
if (high <= low)
{
return;
}
int mid = (high - low + 1) / 2 + low;
Merge_Sort(arr,low,mid-1,tempArr);
Merge_Sort(arr,mid,high,tempArr);
Merge_Arr(arr, low, mid, high, tempArr);
}
void Merge_Arr(int[] arr, int low, int mid, int high, int[] tempArr)
{
int start = low;
int left = low;
int leftEnd = mid - 1;
int right = mid;
int tempIndex = 0;
while (left <= leftEnd && right <= high)
{
if (arr[left] <= arr[right])
{
tempArr[tempIndex++] = arr[left++];
}
else
{
tempArr[tempIndex++] = arr[right++];
}
}
while (left <= leftEnd)
{
tempArr[tempIndex++] = arr[left++];
}
for (int i = 0; i < tempIndex; i++)
{
arr[start++] = tempArr[i];
}
}
Lua实现
--归并排序
function MergeSort(arr)
local tempArr = {}
MSort(arr,1,#arr,tempArr)
end
function MSort(arr,low,high,tempArr)
if low < high then
local midIndex = math.modf((high-low+1)/2+low)
MSort(arr,low,midIndex-1,tempArr)
MSort(arr,midIndex,high,tempArr)
Merge(arr,low,midIndex,high,tempArr)
end
end
function Merge(arr,low,mid,high,tempArr)
local leftStart = low
local leftEnd = mid-1
local rightStart = mid
local rightEnd = high
local tempIndex = 1
while leftStart <= leftEnd and rightStart <= rightEnd do
if arr[leftStart] <= arr[rightStart] then
tempArr[tempIndex] = arr[leftStart]
tempIndex = tempIndex + 1
leftStart = leftStart + 1
else
tempArr[tempIndex] = arr[rightStart]
tempIndex = tempIndex + 1
rightStart = rightStart + 1
end
end
while(leftStart <= leftEnd) do
tempArr[tempIndex] = arr[leftStart]
tempIndex = tempIndex + 1
leftStart = leftStart + 1
end
for i = 1,tempIndex-1 do
arr[low] = tempArr[i]
low = low+1
end
end
折半插入排序
通过折半查找,将一个记录插入到已经排好序的有序表中,并得到一个新的、记录增1的有序表。
C#实现
public void BinaryInsertionSort(int[] array)
{
int length = array.Length;
for (int i = 1; i < length; i++)
{
int temp = array[i];
int low = 0;
int high = i - 1;
while (low <= high)
{
int mid = (low + high) / 2;
if (temp < array[mid])
{
high = mid - 1;
}
else
{
low = mid + 1;
}
}
for (int j = i - 1; j >= high + 1; j--)
{
array[j + 1] = array[j];
}
array[high + 1] = temp;
}
}
Lua实现
--二分插入排序
function BinaryInsertionSort(arr,length)
for i=2,length do
temp=arr[i]
low=1
high=i-1
while(low<=high)do
mid=math.floor((low+high)/2)
if(temp<arr[mid]) then
high=mid-1
else
low=mid+1
end
end
for j=i-1,high+1,-1 do
arr[j+1]=arr[j]
end
arr[high+1]=temp
end
end
基数排序
C#实现
public override void Sort(int[] arr)
{
//求出序列中最大的元素
int max = arr[0];
foreach(var item in arr)
{
max = item > max ? item : max;
}
//求出最大的位数
int maxPlace = 1;
while (max != 0)
{
max /= 10;
maxPlace++;
}
//初始化10个桶,分别标志为0-9
List<List<int>> buckets = new List<List<int>>();
for(int i = 0;i < 10; i++)
{
buckets.Add(new List<int>());
}
for(int i = 1;i <= maxPlace; i++)
{
int standard = (int)Math.Pow(10, i);
//按照位数值存入桶中
foreach (var item in arr)
{
int placeValue = (item % standard) / (standard / 10);
buckets[placeValue].Add(item);
}
//按顺序从桶中取出值重新放入数组中
int index = 0;
foreach(var bucket in buckets)
{
foreach(var value in bucket)
{
arr[index++] = value;
}
bucket.Clear();
}
}
}
计数排序
C#实现
public override void Sort(int[] arr)
{
//先求出序列中最大最小值
int max = arr[0];
int min = arr[0];
foreach(var item in arr)
{
max = item > max ? item : max;
min = item < min ? item : min;
}
//初始化辅助数组的长度
int length = max - min+1;
var bucket = new int[length];
foreach(var item in arr)
{
bucket[item-min]++;
}
int index = 0;
for(int i = 0;i < bucket.Length; i++)
{
while (bucket[i] != 0)
{
arr[index++] = i + min;
bucket[i]--;
}
}
}