一、算法原理
归并排序(Merge sort)是一种建立在归并操作上的递归排序算法,该算法是采用分治法的一个典型的应用,归并排序将一个数组递归地分成两半分别排序,然后将结果归并起来。归并排序是一种稳定的算法,对任意长度为n的数组的排序时间与nlogn成正比,但它需要额外空间的规模与n成正比。
二、算法描述
- 递归自顶向下
- 把长度为n的数组分成两半
- 对这两个子数组分别递归地采用归并排序
- 将两个排序好的子数组归并成一个排序数组
- 迭代自底向上
- 实现归并的另一种方式是自底向上地先归并微型数组,然后再成对归并得到的子数组,直到将数组全部归并在一起,此时数组就是整体排序的。
- 首先两两归并,然后四四归并,再之后是八八归并,一直下去。
- 在每一轮归并中,最后一次归并的第二个子数组规模可能比第一个子数组小,下面示例代码的归并方法考虑到了这种情况。
三、算法复杂度
- 时间复杂度,最佳情况T(n) = O(nlogn),最差情况T(n) = O(nlogn),平均情况T(n) = O(nlogn)
- 空间复杂度,需要与数组规模n成正比的辅助空间,O(n)
三、示例代码
//归并方法
void merge(int a[], int r[], int low, int mid, int high)
{
int i = low, j = mid + 1; //记录待归并元素位置
for (int k = low; k <= high; ++k) //辅助数组
r[k] = a[k];
for (int k = low; k <= high; k++)
{
if (i > mid) a[k] = r[j++]; //左半边用尽 取右半边元素
else if (j > high) a[k] = r[i++]; //右半边用尽 取左半边元素
else if (r[j] < r[i]) a[k] = r[j++]; //右半边元素小 取右半边元素
else a[k] = r[i++]; //左半边元素小或相等 取左半边元素
}
}
//归并排序
//递归实现
void MergeSortCore(int a[], int r[], int low, int high)
{
if (high <= low)
return;
int mid = low + (high - low) / 2;
MergeSortCore(a, r, low, mid); //排序左半边
MergeSortCore(a, r, mid + 1, high); //排序右半边
merge(a, r, low, mid, high); //归并
}
void MergeSort(int a[], int length)
{
if (a == NULL || length <= 0)
{
printf("输入数组错误!\n");
return;
}
int r[length]; //建立辅助数组
MergeSortCore(a, r, 0, length - 1);
}
//迭代实现
void MergeBUSort(int a[], int length)
{
int r[length]; //创建辅助数组
for(int sz = 1; sz < length; sz <<= 1) //sz是每一轮归并时子数组的规模
for(int low = 0; low < length - sz; low += (sz << 1))
{
int mid = low + sz - 1;
int high = low + sz + sz - 1;
high = high < length ? high : length; //考虑到最后归并的后一个子数组的规模可能较小
merge(a, r, low, mid, high);
}
}