归并排序是一种重要的排序方法,虽然并不能算作最优的排序方法,但排序的原理在很多情况下都能引用到,比如求逆序数。
基本原理
1.可以在O(n)时间内将两个有序序列合并为一个有序序列:若给出两个同序排列的序列,若要将两段序列合并为一段新的有序序列只需要逐次将两段序列的段首元素中关键字较大的一个取出放入新的有序序列的末尾,当两段序列全部元素取出时新的序列将包含全部元素并且有序。
2.只含单个元素的序列有序:一个序列只有一个元素时序列为有序序列。
根据上面两个性质,先不断地通过二分将含N个元素的待排序序列划分为N段每段只含一个元素的子段,根据原理2,此时这N段子段全部有序,然后再将这N段序列按原理1的方法不断两两合并,不断合并为N/2段,N/4段,N/8段.......有序序列,最终合并为一段长度为N的序列,则序列已经排好序。
算法的实现
通过递归将序列不断二分,当序列长度为1时结束递归,这时再按照划分时序列间确定的关系进行归并。
归并时需要两个临时数组,可以在两个辅助数组的末尾额外添加一个哨兵,关键字设置为无限大,则将不存在比哨兵关键字更大的元素,之后在合并中就只需要比较关键字的大小而不再需要去判断是否某个序列已经到了末尾。
算法的时间复杂度为O(nlogn),空间复杂度为O(n)。
具体代码:
- #include<iostream>
- using namespace std;
- const int INF=1e9;
- void mergesort(int* Array,int left,int right){
- int middle=(left+right)/2;
- if(middle>left)mergesort(Array,left,middle); //展开递归
- if(middle+1<right)mergesort(Array,middle+1,right);
- int *l=new int[middle-left+2],*r=new int[right-middle+1];
- for(int i=left;i<=middle;i++)l[i-left]=Array[i];
- for(int i=middle+1;i<=right;i++)r[i-middle-1]=Array[i];
- l[middle-left+1]=r[right-middle]=INF; //设置哨兵
- int a=0,b=0;
- for(int i=left;i<=right;i++){ //进行归并
- if(l[a]<r[b])Array[i]=l[a++];
- else Array[i]=r[b++];
- }
- }
- int main(){
- int p[105];
- for(int i=0;i<100;i++)p[i]=rand();
- mergesort(p,0,99); //测试
- for(int i=0;i<100;i++)cout<<p[i]<<endl;
- }