— 八大排序算法
插入排序:直接插入排序、希尔排序
选择排序:简单选择排序、堆排序
交换排序:冒泡排序、快速排序
归并排序
基数排序
1.1 直接插入排序
基本思想:将一个记录插入到已排序好的有序表中,从而得到一个新记录数增1的有序表。具体来说就是,先将序列的第1个记录看成是一个有序的子序列,然后从第2个记录逐个进行插入,直至整个序列有序为止。
算法步骤:
1. 将序列的第一个元素视为有序子序列①,第二个元素作为待排序元素和有序子序列①进行比较插入,得到有序子序列②;
2. 序列的第三个元素作为待排序元素,和有序子序列②进行比较插入,得到有序子序列③;
......
3. 序列的最后一个元素作为待排序元素,和前面的有序子序列进行比较插入,得到整个有序序列。
具体过程:
排序趟数控制 序列(49 38 65 27 76 40 )
i=1 38 49 ## ## ## ## (38为待排序元素,和有序子序列49进行比较插入后)
i=2 38 49 65 ## ## ##
i=3 27 38 49 65 ## ##
i=4 27 38 49 65 76 ##
i=5 27 38 40 49 65 76
代码实现:
交换函数代码
public void swap(ref int a ,ref int b)
{
int temp = a;
a = b;
b = temp;
}
///
/// 【直接插入法】
///
///
public void InsertSort(int[] arr)
{
for(int i=1;i= 0)&&(arr[j]>temp);j--) //寻找插入位置(j)并后移元素
{
arr[j + 1] = arr[j];
}
arr[j+1] = temp; //将待排序元素插入到指定位置(最后一次j进行了自减,所以这里下标是j+1)
}
}
1.2 希尔排序
基本思想:先将整个待排序的记录序列分割成为若干子序列分别进行直接插入排序,待整个序列中的记录“基本有序”时,再对全体记录进行依次直接插入排序
算法步骤:
1. 选择增量gap,将整个序列分为N组子序列,对N组子序列分别进行直接插入排序;
2. 选择增量gap=gap/2,将整个子序列分为M组,对M组子序列分别进行直接插入排序;
......
3. 直到增量gap=2/2=1,此时整个序列为一组,对整体再进行一次直接插入排序。
具体过程:
排序趟数控制 序列 49 38 65 27 76 40
gap=lenth/2=3 27 38 40 49 76 65 ( 序列分组为[49,27]、[38,76]、[65,40] )
gap=3/2=1 27 38 40 49 65 76 ( 整体为一组 )
代码实现:
///
/// 【希尔排序】
///
///
public void ShellSort(int[] arr)
{
for(int gap = arr.Length / 2;gap>=1; gap= gap / 2)
{
for(int i=gap;i< arr.Length;i++) //对一定增量下的子序列分别进行直接插入排序
{
int temp = arr[i]; //待排序元素
int j = i - gap;
for(;(j>=0)&&(arr[j]>temp);j=j-gap)
{
arr[j + gap] = arr[j];
}
arr[j + gap] = temp;
}
}
}
基本思想:每趟比较中选择出最小值作为序列的第I个元素(I=1~n-1)。具体来说就是,选出最小数与第1个位置的数交换;然后在剩下的数当中再选出最小数与第2个位置的数交换,依次类推。
算法步骤:
1. 将最小值索引初始化序列首位,将两两比较中的较小值和后续元素继续比较,确定整个序列最小值的位置,将该位置元素和元素首位进行交换;
2. 将最小值索引初始化为序列第2位,同样的方法确定后面序列的最小值,和第2个位置的数交换;
......
3. 最小值索引初始化为序列第N-1位,和序列最后一位数比较确定最小值,排序完成。
具体过程:
排序趟数控制 序列(49 38 65 27 76 40 )
i=0 27 38 65 49 76 40
i=2 27 38 49 65 76 40
i=3 27 38 40 65 76 49
i=4 27 38 40 49 65 76
i=5 27 38 40 49 65 76
代码实现:
///
/// 【选择排序法】
///
///
///
public void SelectionSort(int[] arr)
{
int minIndex;
for (int i=0;i
3.1 冒泡排序法
基本思想:从序列第一个元素开始,两两比较,如果前面值大于后面值,则交换两个元素的位置,把最大值往后移,一趟比较后最大值移动到最后位置。
代码实现:
///
/// 【冒泡排序法】
///
///
///
public void BubbleSort(int[] arr)
{
for(int i = 0; i < arr.Length; i++)
{
for(int j=0;j< arr.Length-i-1;j++)
{
if(arr[j]>arr[j+1])
{
swap(ref arr[j+1], ref arr[j]);
}
}
}
}
算法改进1:设置标志位,如果某趟循环中没有任何数据交换发生,说明序列已排序完成,则不需要再进行剩余的循环
public void BubbleImprove1(int[] arr)
{
bool isExchange = true;
for (int i = 0; i < arr.Length &&(isExchange); i++)
{
isExchange = false;
for (int j = 0; j < arr.Length - i - 1; j++)
{
if (arr[j] > arr[j + 1])
{
isExchange = true;
swap(ref arr[j + 1], ref arr[j]);
}
}
}
}
算法改进2:原始算法中,每趟排序的两两比较,并不是一直都会交换,记录最后一次发生交换的位置( 该位置之后的元素已排序完成 ) ,以此控制每趟两两比较的次数,减少排序趟数
public void BubbleImprove2(int[] arr)
{
int i = arr.Length - 1;
while(i>0)
{
int lastExchange = 0;
for (int j = 0; j < i; j++)
{
if (arr[j] > arr[j + 1])
{
lastExchange = j;
swap(ref arr[j + 1], ref arr[j]);
}
}
i = lastExchange;
}
}
public void BubbleImprove3(int[] arr)
{
for (int low = 0, high = arr.Length - 1; low < high; --high, ++low)
{
int j = 0;
for (j = low; j < high; j++)
{
if (arr[j] > arr[j + 1])
{
swap(ref arr[j + 1], ref arr[j]);
}
}
for(j=high-1;j>low;j-- )
{
if (arr[j] < arr[j - 1])
{
swap(ref arr[j - 1], ref arr[j]);
}
}
}
}
基本思想:通过一趟排序将要排序的数据分割成独立的两部分,一部分数据比另部分数据都要小,再按此方法对两部分数据分别进行快速排序,以此递归。
一趟快速排序具体来说就是,选择一个数据(通常选第一个或最后一个)作为关键数据,然后将所有比它小的数都放在前面,所有比它大的数都放在它后面
算法步骤:
1. 定义序列第一个元素为基准元素pos,先从序列末尾开始,反向顺序和基准元素比较,直到找到比基准小的一个元素,和序列开头数据交换。
再从序列开头开始,正向顺序和基准元素比较,直到找到比基准大的一个元素,和序列末尾数据交换;
2. 不断循环上述过程,直到序列开头索引大于等于序列末尾索引;
3. 上述过程完成了一趟快速排序,序列被分割成两部分,再对两部分数据重复上述快速排序,以此递归。
具体过程:
排序趟数控制 序列 49 38 65 27 76 40
startIndex < endIndex 40 38 65 27 76 49 (1:反向查找)
40 38 49 27 76 65 (1:正向向查找)
(40 38 27) (49 76 65) (2:一趟快速排序完成,序列被分割成较小数据和较大数据两部分)
代码实现:
///
/// 【快速排序法】
///
///
///
public void SpeedSort(int[] arr,int startIndex,int endIndex)
{
if (startIndex >= endIndex) return;
int boundary = Boundary(arr, startIndex, endIndex);
SpeedSort(arr, startIndex, boundary-1);
SpeedSort(arr, boundary+1, endIndex);
}
int Boundary(int[] arr, int startIndex, int endIndex)
{
int pos = arr[startIndex]; //定义基准为序列的第一个元素
while(startIndex < endIndex)
{
while ((startIndex < endIndex) && (arr[endIndex] >= pos)) endIndex--;
swap(ref arr[startIndex], ref arr[endIndex]);
while ((startIndex < endIndex) && (arr[startIndex] <= pos)) startIndex++;
swap(ref arr[startIndex], ref arr[endIndex]);
}
arr[startIndex] = pos;
return startIndex;
}