1. 什么是归并?
归并:把两个或多个已经有序的序列合并成一个。
特点:M路归并,每选出一个元素就需要对比关键字m-1次。
2. 算法思路
对待排序元素序列进行 2路归并,首先将序列分成左右子序列,然后分别对该左右子序列进行递归拆分,直到最后分解为单个元素的左右子序列,两两进行归并排序,整个归并过程形态上就是棵倒立的二叉树。
算法步骤:
- 若Low<high,则将序列从中间mid = (low+high) / 2 分开
- 对左半部分[low, mid] 递归地进行归并排序
- 对右半部分[mid+1, high] 递归地进行归并排序
- 将左右两个有序子序列Merge为一个。
归并步骤如下图所示:
- 空间复杂度:O(n)。
- 时间复杂度:O(nlog2(n))。
- 算法稳定性:稳定。
- 适用性:可用于顺序表和链表。
3. 实现代码(C语言)
#include <stdio.h> // 输入输出
#include <windows.h> // system函数
#define MaxSizeG 8
int *B = (int *)malloc(MaxSizeG * sizeof(int)); // 辅助数组
// 归并
void Merge(int *arr, int low, int mid, int high)
{
int i, j, k;
for (k = low; k <= high; k++)
{
B[k] = arr[k]; // 将待排序元素全部存入辅助数组中
}
for (i = low, j = mid + 1, k = i; i <= mid && j <= high; k++)
{
// 将较小的值复制到原数组中
if (B[i] < B[j])
{
arr[k] = B[i];
i++;
}
else
{
arr[k] = B[j];
j++;
}
}
// [mid,high]之间的元素已全部排完序
while (i <= mid)
{
arr[k++] = B[i++];
}
// [low,mid]之间的元素已全部排完序
while (j <= high)
{
arr[k++] = B[j++];
}
}
// 归并排序
void MergeSort(int *arr, int low, int high)
{
if (low < high)
{
// 每次递归都将待排序元素序列分成两部分
int mid = (low + high) / 2;
MergeSort(arr, low, mid); // dio左半部分归并排序
MergeSort(arr, mid + 1, high); // 对半部分归并排序
Merge(arr, low, mid, high); // 归并
}
}
// 打印
void PrintList(int *A, int n)
{
int i;
for (i = 0; i < n; i++)
{
printf("%d", A[i]);
printf("\n");
}
}
int main()
{
int G[MaxSizeG] = {87, 75, 66, 52, 14, 71, 99, 91};
// 递归排序
MergeSort(G, 0, MaxSizeG - 1);
PrintList(G, MaxSizeG);
printf("\n");
system("pause"); // 避免exe程序自动退出
return 0;
}