归并排序
归并定义:将两个或以上的有序表组合成一个新的有序表。
归并排序:假设初始序列含义n个记录,则可以看成是n个有序的子序列,每个子序列的长度为1,然后两两归并,知道得到一个长度为n的有序序列为止——2路归并排序。
归并排序过程:逐一两两分开,再两两归并
逐一两两分开,最终分成一个个单独的元素,再一一进行比较、合并。
代码分析:
代码主要分为两个部分,分解过程和合并过程
利用递归来实现分解和合并的过程,其中if(s==t) TR1[s]=SR[s];表示分解完毕,开始递归返回进行合并
void MSort(int SR[],int TR1[],int s,int t){
int m;
int TR2[MAX+1];
if(s==t) TR1[s]=SR[s];// 递归返回
else{
m = (s+t)/2;
MSort(SR,TR2,s,m);// 递归将其细分为一个个,再两两合并
MSort(SR,TR2,m+1,t);
// 将左右分别排好序后再合并
Merge(TR2,TR1,s,m,t);
}
}
复杂度分析:
一趟归并排序需将SR[1]–Sr[n]汇总相邻的长度h有序序列进行两两归并,会访问到数组中的每一个数,故一次递归的复杂度为n,由完全二叉树的性质知,需进行(log2n)次递归,故总的时间复杂度为O(nlog2n)。
归并排序倒过来看就是一棵完成二叉树
归并排序完整代码:(详细注释)
/*
Author:Kim
Data:2020-2-10
Topic:归并排序的递归实现法代码
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 10
// 定义一个用于的排序的顺序表
typedef struct SL {
int r[MAX+1];// 用于存储要排序的数,通常:r[0]作为哨兵或者临时变量
int length;// 用于记录顺序表的长度
}SqList;
//合并函数
void Merge(int SR[],int TR[],int i,int m,int n)
{
int j,k,l;
for(j=m+1,k=i;i<=m && j<=n;k++){// 将SR中记录由小到大地并入TR
if (SR[i]<SR[j])
TR[k]=SR[i++];
else
TR[k]=SR[j++];
}
if(i<=m){
for(l=0;l<=m-i;l++)
TR[k+l]=SR[i+l];// 将剩余的SR[i..m]复制到TR
}
if(j<=n){
for(l=0;l<=n-j;l++)
TR[k+l]=SR[j+l];// 将剩余的SR[j..n]复制到TR
}
}
// 将SR[]递归排序为TR1[]
void MSort(int SR[],int TR1[],int s,int t){
int m;
int TR2[MAX+1];
if(s==t) TR1[s]=SR[s];// 递归返回
else{
m = (s+t)/2;
MSort(SR,TR2,s,m);// 递归将其细分为一个个,再两两合并
MSort(SR,TR2,m+1,t);
// 将左右分别排好序后再合并
Merge(TR2,TR1,s,m,t);
}
}
void MergeSort(SqList *L){
MSort(L->r,L->r,1,L->length);
}
int main() {
SqList t;
t.length = 0;
int a[] = { 20,10,50,90,70,40,80,60,30 };
int i;
for (i = 0; i < 9; i++) t.r[i + 1] = a[i];
t.length = 9;
printf("初始序列:");
for (i = 1; i < 10; i++) printf("%3d", t.r[i]);
printf("\n");
// 归并排序
MergeSort(&t);
printf("归并排序后序列:");
for (i = 1; i < 10; i++) printf("%3d", t.r[i]);
}