归并排序
图片选自菜鸟教程
图片选自
小天狼星_布莱克
结构定义
#include<stdio.h>
#include<stdlib.h>
#define MAXSIZE 100 //排序数组个数最大值
typedef struct {
int a[MAXSIZE + 1]; //a[0]用作哨兵或临时变量
int length; //顺序表长度
}SqList;
思路
原理:假设初始序列有 n 个记录,则可以看成是 n 个有序的子序列,每个子序列长度为 1 ,然后两两归并,得到 [n / 2] ([x]表示不小于 x 的最小整数)个长度为 2 或 1 的有序序列;再两两归并,…… ,重复,直至得到一个长度为 n 的有序序列,这种排序方法称为 2 路归并排序
性能分析
稳定排序
所有记录都要扫描一遍,需进行 logn(都默认log2n) 次(完全二叉树深度)
空间复杂度:递归:O(n + logn);非递归:O(n).
因为递归需要深度为 logn 的栈空间,所以内存大一点
时间复杂度:
归并排序 | 最好情况 | 最坏情况 | 平均情况 |
---|---|---|---|
- | nlogn | nlogn | nlogn |
归并排序(递归)
/* 归并排序 */
/* 封装函数,便于调用 */
void MergeSort(SqList* L)
{
MSort(L->a, L->a, 1, L->length);
}
/* 归并排序算法 */
void MSort(int SR[], int TR1[], int s, int t)
{
int m;
int TR2[MAXSIZE + 1];
if (s == t) //如果子序列个数为 1
TR1[s] = SR[s];
else
{
m = (s + t) / 2; //将SR[s......t]平分为SR[s...m]和SR[m + 1...t]
MSort(SR, TR2, s, m); //递归地将SR[s......m]归并为有序的TR2[s......m]
MSort(SR, TR2, m + 1, t); //递归地将SR[m + 1......t]归并为有序的TR2[m + 1......t]
Merge(TR2, TR1, s, m, t); //将TR2[s...m]和TR2[m + 1...t]归并为有序的TR1[s...t]
}
}
/* 合序归并 */
void Merge(int SR[], int TR[], int i, int m, int n)
{
int j, k;
/* 将SR[i...m]和SR[m + 1...n] 由小到大并入TR */
for (j = m + 1, k = i; i <= m && j <= n; k++)
{
if (SR[i] < SR[j])
TR[k] = SR[i++];
else
TR[k] = SR[j++];
}
if (i <= m) //如果SR[m + 1...n]已经全部填入到TR,但是SR[i...m]还没有全部填入到TR
{
for (int l = 0; l <= m - i; l++)
TR[k + l] = SR[i + l]; //将剩余的SR[i...m]填入到TR
}
else //如果SR[i...m]已经全部填入到TR,但是SR[m + 1...n]还没有全部填入到TR
for (int l = 0; l <= n - j; l++)
TR[k + l] = SR[j + l]; //将剩余的SR[j...n]填入到TR
}
对于Merge()函数中的该代码
/* 将SR[i...m]和SR[m + 1...n] 由小到大并入TR */
for (j = m + 1, k = i; i <= m && j <= n; k++)
{
if (SR[i] < SR[j])
TR[k] = SR[i++];
else
TR[k] = SR[j++];
}
即 将子序列 SR[i…m],SR[m + 1…n] 由小到大并入TR,TR[i…n]有序
归并排序(非递归)
因为递归占内存,所以我们可以用迭代替换递归
/* 归并排序(非递归)*/
void MergeSort2(SqList* L)
{
int* TR = (int*)malloc(L->length * sizeof(int));
int k = 1;
while (k < L->length)
{
MergePass(L->a, TR, k, L->length); //将子序列两两归并入TR
k *= 2; //子序列长度加倍
MergePass(TR, L->a, k, L->length); //将已经两两归并的有序序列再次归并入L->a
k *= 2; //子序列长度加倍
}
}
/* 合序归并(非递归) */
/* s 代表子序列之间相差的个数 ,即 1, 2, 4, 8...... */
void MergePass(int SR[], int TR[], int s, int n)
{
int i = 1;
/* s 代表子序列之间相差的个数 */
while (i <= n - (2 * s) + 1) //两两归并
{
Merge(SR, TR, i, i + s - 1, i + (2 * s) - 1);
i = i + 2 * s;
}
/* 处理最后的尾数 */
if (i < n - s + 1) //归并最后两个序列
Merge(SR, TR, i, i + s - 1, n);
else
//如果只剩下单个子序列,将它直接加入到TR中(不管有序性).
//例:1,2,3,4,5. s = 1. 1与2归并,3与4归并,5归并不了,将5直接加入到TR中
for (int j = i; j <= n; j++)
TR[j] = SR[j];
}