分治法之归并排序
上一篇博文介绍了分治法的思想,这一篇我们来了解一下分治法在排序问题中的应用--二路归并排序MergeSort
所谓归并排序是指将两个或两个以上有序的数列(或有序表),合并成一个仍然有序的数列(或有序表)
算法设计思路:
输入:待排序数组a[n],待排序区间[s,t];
输出:升序序列a[s]~a[t]
1 如果s==t,则待排区间只有一个元素,算法结束
2 计算划分中点 m=(s+t)>>1;
3 对前半个子序列a[s]~a[m]进行升序排列
4 对后半个子序列a[m+1]~a[t]进行升序排列
5 合并两个升序序列a[s]~a[m]和a[m+1]~a[t]
算法实现代码(C++)
#include <stdio.h> const int MAX=20; //合并两个有序数组中的元素到数组b void Merge(int a[],int b[],int s,int m,int t)//算法时间复杂度O(n) { int i=s,j=m+1,k=s; while(i<=m && j<=t)//取较小者放入b[k] { if(a[i]<=a[j]) b[k++]=a[i++]; else b[k++]=a[j++]; } while(i<=m) b[k++]=a[i++]; while(j<=t) b[k++]=a[j++]; } void MergeSort(int a[],int s,int t) { int m,b[MAX]; if(s==t) return ;//平凡问题,递归边界条件,只有一个记录,已经有序 else { m=(s+t)>>1; MergeSort(a,s,m); MergeSort(a,m+1,t); Merge(a,b,s,m,t); for(int i=s;i<=t;i++) a[i]=b[i]; } } extern void test1() { int length,i; int num[MAX]; printf("请输入待排序的数组长度(按ctrl+z结束)\n"); while(scanf("%d",&length)!=EOF) { printf("请依次输入数组元素\n"); for(i=0;i<length;i++) scanf("%d",num+i); MergeSort(num,0,length-1); printf("\n-------------------------------------------\n"); printf("归并排序后输出元素序列\n"); for(int i=0;i<length;i++) printf("%d\t",num[i]); printf("\n"); for(i=0;i<length;i++)//清零 num[i]=0; printf("请输入待排序的数组长度(按ctrl+z结束)\n"); } }
算法实现分析:
空间复杂度:归并排序需要多元序列上的两个子序列操作,因此不能直接在原序列上进行,需要一个与原序列相同的辅助空间,因此空间复杂度为O(n)
时间复杂度:设待排序列个数为n,则执行一趟合并操作算法时间复杂度为o(n),当n=1时,直接返回,即不耗时间T(1)=0;
总的时间复杂度为t(n)=O(nlogn)