一 归并排序
归并排序是将两个或两个以上的有序表组合成一个新的有序表。如待排序表含有n个记录,则可将其视为n个有序的子表,每个子表的长度为1,然后两两归并,得到[n/2]个长度为2或1的有序表;继续两两归并.....如此重复,直到合并成一个长度为n的有序表为止,此排序称为2路归并排序。
二 归并排序的实现
设两段有序表a[low ... mid],b[mid+1 ... high]存放在同一个顺序表中的相邻位置,先将他们复制到辅助数组B中。每次从对应B中的两段取出一个记录进行关键字的比较,将较小者放入a中,当数组b中有一段的下标超出其对应的表长(即该段的所有元素都已复制到a中)时,将另一段中的剩余部分直接复制到a中。
三 归并排序的代码实现
#include <stdlib.h>
#include <stdio.h>
void Merge(int sourceArr[],int tempArr[], int startIndex, int midIndex, int endIndex)
{
int i = startIndex, j=midIndex+1, k = startIndex;
while(i!=midIndex+1 && j!=endIndex+1)
{
if(sourceArr[i] > sourceArr[j])
tempArr[k++] = sourceArr[j++];
else
tempArr[k++] = sourceArr[i++];
}
while(i != midIndex+1)
tempArr[k++] = sourceArr[i++];
while(j != endIndex+1)
tempArr[k++] = sourceArr[j++];
for(i=startIndex; i<=endIndex; i++)
sourceArr[i] = tempArr[i];
}
//内部使用递归
void MergeSort(int sourceArr[], int tempArr[], int startIndex, int endIndex)
{
int midIndex;
if(startIndex < endIndex)
{
midIndex = startIndex + (endIndex-startIndex) / 2;//避免溢出int
MergeSort(sourceArr, tempArr, startIndex, midIndex);
MergeSort(sourceArr, tempArr, midIndex+1, endIndex);
Merge(sourceArr, tempArr, startIndex, midIndex, endIndex);
}
}
int main(int argc, char * argv[])
{
int a[8] = {49,38,65,97,76,13,27,49};
int i, b[8];
MergeSort(a, b, 0, 7);
for(i=0; i<8; i++)
printf("%d ", a[i]);
printf("\n");
return 0;
}
实现结果:
四 算法的性能分析
算法 | 最好时间 | 最坏时间 | 平均时间 | 额外空间/空间复杂度 | 稳定性 |
---|---|---|---|---|---|
快速插入排序 | O(nlog2^n) | O(nlog2^n) | O(nlog2^n) | O(n) | 稳定 |
空间效率:Marge()操作中,辅助空间刚好为n个单位,所有算法的空间复杂度为O(n)。
时间效率:每趟归并的时间复杂度为O(n),共需要进行log2^n趟归并,所以算法的时间复杂度为O(nlog2^n)。
稳定性:由于Marge()操作不会改变相同关键字记录的相对次序,所以2路归并排序算法是一种稳定的排序方法。
一般而言,对于N个元素进行k路归并排序时,排序的趟数m满足k^m = N,从而m = logk^N。这和前面的2路归并时一致的。