归并排序
基本思想:将两个或两个以上的有序子序列“归并”为一个有序子序列。在内部排序中,通常采用的是2-路归并排序,即将两个位置相邻的有序子序列“归并”为一个有序序列。类似于快排,其使用的也是分治的策略。
二路归并排序
基本思想:将有n个记录的原始序列看做n个有序子序列,每个子序列的长度为1,然后从第1个子序列开始,把相邻的子序列两两合并,得到n/2个长度为2或1的子序列(当子序列的个数为奇数是,最后一组合并得到的序列长度为1),我们把这一过程称为一次归并排序,对一次归并排序的n/2个子序列采用上述方法继续顺序成成对归并,如此重复,当最后得到长度为n的一个子序列时,该子序列便是原始序列归并后的有序序列。
过程如图所示:
第一趟:将列表中的11个元素看成11个有序的序列,每个子序列的长度为1,然后两两归并,得到5个长度为2和1个长度为1的有序子序列。
第二趟:将6个有序子序列两两合并,得到2个长度为4和1个长度为3的有序子序列。
第三趟:将2个长度为4的有序子序列归并,得到第3趟归并结果。
第四趟:将长度为8有序子序列和长度为3的有序子序列归并,得到第4趟归并结果,是长度为11的一个有序子序列。
时间复杂度:O(nlog2n)
代码实现:
/// <summary>
/// 归并排序
/// </summary>
/// <paramname="arr"></param>
public static void mergeSort(ref int[]arr)
{
int k = 1;
while (k < arr.Length)
{
arr=merge(arr, k);
k *= 2;
}
}
private static int[] merge(int[]arr,int len)
{
int m = 0;//临时顺序表的起始位置
int l1 = 0;//第一个有序表的起始位置
int h1;//第一个有序表的结束位置
int h2,l2,i = 0,j = 0;
int[] tarr = new int[arr.Length];
//归并处理
while (l1 + len < arr.Length)
{
l2 = l1 + len;//第二个有序序列的起始位置
h1 = l2 - 1;//第一个序列的结束位置
//第二个有序表的结束位置
h2 = l2 + len - 1 <arr.Length ? l2 + len - 1 : arr.Length - 1;
j = l2; i = l1;
//两个有序表中的记录没有排序完
while (i <= h1 && j<= h2)
{
if (arr[i] <= arr[j])
{
tarr[m++] = arr[i++];
}
else
{
tarr[m++] = arr[j++];
}
}
//第一个有序表中还有记录没有排序完
while (i <= h1)
{
tarr[m++] = arr[i++];
}
//第二个有序表中还有记录没有排序完
while (j <= h2)
{
tarr[m++] = arr[j++];
}
l1 = h2 + 1;
}
i = l1;
//原顺序表中还有记录没有排序完
while (i < arr.Length)
{
tarr[m++] = arr[i++];
}
return tarr;
}
分配排序
分配排序的基本思想:排序过程无须比较关键字,而是通过“分配”和“收集”过程来实现排序。他们的时间复杂度可达到线性阶:O(n)
(1) 最高位优先法(MSD法):先按最主位关键码进行排序,分成不同的组,再按次主位关键码进行排序,进行细化,依次类推,然后将各个子序列连接起来,便得到一个有序序列。
(2) 最次位优先法(LSD法):与MSD方向相反。