【转载】高效排序——归并排序

在网上看到一篇不错的博客,在此转载,原文地址

我又来写博客了,上面两篇写了两篇难度比较大的,实际上在NOIP中很少用到,所以本人决定写一个比较好懂而且NOIP中实用的算法。这次的话,就写个归并排序吧。

我是一名C++ 选手,所以我知道很多C++ 选手都会使用STL标准模版库,包括sort(排序),但是有的时候有的题目的话,就会出现一些很明显的问题,就是STL所解决不了的(例如有特殊要求的题目,时间卡得很死的题目),所以本人正在学习STL模版的具体实现,我也强烈建议C++选手能懂得STL的具体实现(当然在NOIP中能使用STL最好是尽量使用,多争取时间来写别的题目,但是注意STL模版的时间复杂度比较高,容易超时。在平时刷题的时候,写一遍STL熟悉一下,然后最好再自己不用STL实践一下)

今天我来讲一下归并排序。为什么我要讲这个排序,而先不讲快速排序和桶排序呢?实质上是有一个比较著名的题型与其相关——就是求一个序列中的逆序对(在数列中有1<=i,j<=n,i

void merge_sort(int* A,int l,int r,int* T){//A为数组序列,T为临时空间 
    if(r - l >1){//因为如果区间内只有一个数的话,就不必排序 
        int m = l + (r - l)/2;
        int p = l,q = m,i=l;
        merge_sort(A,l,m,T);
        merge_sort(A,m,r,T);
        while(p < m || q < r){
            if(q >= r || (p < m && A[p] <= A[q]))T[i++] = A[p++];//从左半部分复制到临时空间 
            else T[i++] = A[q++];//从右半部分复制到临时空间 
        }
        for(int i = l;i <= r;i++)A[i] = T[i]; //从临时空间复制回A数组 
    }
}

这里呢就是归并排序的核心代码,下面我们来讲一下逆序对问题

关于这个逆序对的问题,其实也很简单,上面我们也给出了逆序对的定义,其实在归并排序的时候,我们完全可以金鑫逆序对的计算,其实道理很简单。当我们归并排序的时候加一步,就是当我们从右半部分的元素放入临时空间T的时候,会产生m-p个逆序对,所以其实在我们进行比较排序,将右半部分的元素放入临时空间T的时候,我们只需要同时统计逆序对的个数就可以了,其实就是加了一条语句:当我们以cnt变量来计数的时候,那么在else语句中再加一条cnt += m-p;即可。那么我还是给出核心代码,核心代码如下:

void merge_sort(int* A,int l,int r,int* T){//A为数组序列,T为临时空间 
    if(r - l >1){//因为如果区间内只有一个数的话,就不必排序 
        int m = l + (r - l)/2;
        int p = l,q = m,i=l;
        merge_sort(A,l,m,T);
        merge_sort(A,m,r,T);
        while(p < m || q < r){
            if(q >= r || (p < m && A[p] <= A[q]))T[i++] = A[p++];//从左半部分复制到临时空间 
            else{
                T[i++] = A[q++];//从右半部分复制到临时空间 
                cnt += m-p;//统计逆序对数 
            } 
        }
        for(int i = l;i <= r;i++)A[i] = T[i]; //从临时空间复制回A数组 
    }
}
 逆序对

逆序对

好了,这次归并排序的讲解博客就到这里了,其实这个归并排序,是所有排序算法中最为重要的一个,也是效率最高的一个,希望大家在看不懂的地方给我提下意见,好能让我修改一下,谢谢大家啦,这样我会有更充足的动力写下去。

转载于2015年8月29日。

posted on 2015-08-29 14:44  MagHSK  阅读(118)  评论(0编辑  收藏  举报