归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。
归并的基本思想是合并多路有序数组,通常我们考虑两路归并算法。
归并排序是稳定的,这是因为,在进行多路归并时,如果各个序列当前元素均相等,可以令排在前面的子序列的元素先处理,不会打乱相等元素的顺序。
考虑元素比较次数,两个长度分别为m和n的有序数组,每次比较处理一个元素,因而合并的最多比较次数为(m+n-1),最少比较次数为min(m,n)。对于两路归并,序列都是两两合并的。不妨假设元素个数为n=2^h,
第一次归并:合并两个长度为1的数组,总共有n/2个合并,比较次数为n/2。
第二次归并:合并两个长度为2的数组,最少比较次数是2,最多是3,总共有n/4次,比较次数是(2~3)n/4。
第三次归并:合并两个长度为4的数组,最少比较次数是4,最多是7,总共有n/8次合并,比较次数是(4-7)n/8。
第k次归并:合并两个长度为2^(k-1)的数组,最少比较次数是2^(k-1),最多是2^k-1,总共合并n/(2^k)次,比较次数是[2^(k-1)~(2^k-1)](n/2^k)=n/2~n(1-1/2^k)。
按照这样的思路,可以估算比较次数下界为n/2*h=nlog2(n)/2。上界为n[h-(1/2+1/4+1/8+...+1/2^h)]=n[h-(1-1/2^h)]=nlog2(n)-n+1。
综上所述,归并排序比较次数为nlog2(n)/2~nlog2(n)-n+1。
归并排序引入了一个与初始序列长度相同的数组来存储合并后的结果,因而不涉及交换。
例如设有数列{6,202,100,301,38,8,1}
初始状态:6,202,100,301,38,8,1
第一次归并后:{6,202},{100,301},{8,38},{1},比较次数:3;
第二次归并后:{6,100,202,301},{1,8,38},比较次数:4;
第三次归并后:{1,6,8,38,100,202,301},比较次数:4;
总的比较次数为:3+4+4=11;
逆序数为14;
第一步中比较三次指的是第一次让6与202比,第二次100与301比第三次38与8比
第二步中比较四次分别是第一次100与6比,第二次100与202比,第三次是202与301比,第四次是1与8比
第三步中比较四次分别是第一次1与6比,第二次8与6比,第三次8与100比,第四次38与100比
所以一共11次
逆序数为14
什么是逆序数?如果一对数的前后位置与大小顺序相反,即前面的数大于后面的数,那么它们就称为一个逆序。一个排列中逆序的总数就称为这个排列的逆序数。
例如4 3 2 1,43,41,42,32,31,21,均为逆序数,一共6对
归并代码:
void hebingsort(int l,int r)
{
if(l==r)
return ;
int mid=(l+r)>>1;
hebingsort(l,mid);
hebingsort(mid+1,r);
int i=l,j=mid+1,k=l;
while(i<=mid&&j<=r)
{
if(a[i]<=a[j])
{
c[k++]=a[i++];
}
else
{
c[k++]=a[j++];
ans+=(mid-i+1);
}
}
while(i<=mid)
{
c[k++]=a[i++];
}
while(j<=r)
{
c[k++]=a[j++];
}
for(i=l;i<=r;i++)
a[i]=c[i];
}