归并排序
归并排序,顾名思义,是一种排序算法。速度应该不错(由于长期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]; } } }
原文:https://www.cnblogs.com/clockwhite/p/11623252.html