归并排序——逆序对

归并排序

  归并排序,顾名思义,是一种排序算法。速度应该不错(由于长期sort我就只知道sort最快[狗头]),实际上他的思想是分治。

  分治分治,分而治之。那么对于一个数的序列怎么去分而治之呢?如果我们面对目前两个数列:1 2 3 和 4 5 6。将这两个接在一起形成一个有序的序列,是十分简单的。直接将它们接在一起就行了。所以说分,是分成两部分,由于分治的基本思想就是我的子问题先解决再轮到我,所以这两个序列肯定是有序的。

  当然算法主要是解决那些毒瘤情况(而非上文中的超简单例子)。面对这个:1 4 5和2 3 6。这种例子肯定不是那么好拼的,那么我们分别用两个指针,一个新的答案数组。这两个指针分别指向这两个序列中的数。然后比较,谁小谁先进答案数组,直到完为止。是不是很简单呢?

逆序对——归并排序的实际应用

  逆序对,是指 i<j且ai>aj这样的情况。怎么求出逆序对就是归并排序要做的事情。

  对于一个数列,它的逆序对由两个子序列中的逆序对以及跨子序列的逆序对组成。很显然,两个子序列中的答案早以计算好(分治特性)。那么如何求出“跨区间”的逆序对呢?

  在归并排序两个指针对比的时候,我们可以找到它们之间的大小关系。记两指针分别为i j 如果 ai<=aj,那么对答案没有影响。否则的话就意味着逆序对出现。由于子序列满足有序,所以有i~序列末尾 的数都比aj大,也就是同时出现了多个逆序对,直接加上这么多个答案就行了。

code

void gb(int l,int r){
    if(l==r)return;
    else{
        int mid=(l+r)>>1,p=0;
        gb(l,mid);gb(mid+1,r);
        int i=l,j=mid+1;
        while(i<=mid&&j<=r){
            if(a[i]<=a[j]){
                c[++p]=a[i];
                i++;
            }
            else{
                c[++p]=a[j];
                j++;
                ans+=(mid-i+1);
            }
        }
        while(i<=mid)c[++p]=a[i++];
        while(j<=r)c[++p]=a[j++];
        for(i=1;i<=p;++i){
            a[l+i-1]=c[i];
        }
    }
}
View Code

猜你喜欢

转载自www.cnblogs.com/clockwhite/p/11623252.html