首先将a[0…n-1]看成是n个长度为1的有序表,将相邻的k(k≥2)个有序子表成对归并,得到n/k个长度为k的有序子表,然后再将这些有序子表继续归并,得到n/k2个长度为k2的有序子表,如此反复进行,最后得到一个长度为n的有序表。
若k=2,即归并在相邻的两个有序子表中进行,称为二路归并排序,若k>2,即归并操作在相邻的多个有序子表中进行,称为多路归并排序。
循环⌈log2n⌉次,length依次取1,2,4…每次执行以下步骤:
//相邻两个子表的合并
void Merge(int a[],int low,int mid,int high){
//a[low..mid]+a[mid+1..high]=a[low..high]
int* tmpa;
int i = low;
int j = mid+1;
int k = 0;
tmpa = (int*)malloc((high-low+1)*sizeof(int));
while(i<=mid&&j<=high){
if(a[i]<=a[j]){ //将第1子表中元素放入tmpa
tmpa[k] = a[i];
++i;
++k;
}
else{ //将第2子表中元素放入tmpa
tmpa[k] = a[j];
++j;
++k;
}
}
while(i<=mid){
tmpa[k] = a[i];
++i;
++k;
}
while(j<=high){
tmpa[k] = a[j];
++j;
++k;
}
for(k = 0,i = low;i<=high;++i,++k)
a[i] = tmpa[k];
free(tmpa);
}
//一趟二路归并排序
void MergePass(int a[],int length,int n){
int i;
for(i = 0;i+2*length-1<n;i+=2*length) //归并length长的两相邻子表
Merge(a,i,i+length-1,i+2*length-1);
if(i+length-1<n) //余下两个子表,后者长度小于length
Merge(a,i,i+length-1,n-1); //归并这两个子表
}
//二路归并算法
void MergeSort(int a[],int n){
int length;
for(length = 1;length<n;length=2*length)
MergePass(a,length,n);
}
示例结果
a[8]={1,3,9,5,6,4,7,2};
第1趟归并排序结果为:1 3 5 9 4 6 2 7
第2趟归并排序结果为:1 3 5 9 2 4 6 7
第3趟归并排序结果为:1 2 3 4 5 6 7 9
Process returned 0 (0x0) execution time : 0.056 s
Press any key to continue.
设归并排序的当前区间是a[low…high],则递归归并的两个步骤如下:
//二路归并算法
void MergeSort(int a[],int low,int high){
int mid;
if(low<high){ //子序列有两个或两个以上元素
mid = (low+high)/2; //取中间位置
MergeSort(a,low,mid); //对a[low..mid]子序列排序
MergeSort(a,mid+1,high); //对a[mid+1..high]子序列排序
Merge(a,low,mid,high); //将两子序列合并,见上面算法
}
}
问题描述:设a为一个含n个整数的序列,整数各不相同,如果存在i j 使得1≤i
3,1,4,5,2中有逆序对(3,1) (3,2) (4,2) (5,2)
设计算法求给定数组a中逆序对的个数
解决方法:采用二路归并(这里使用自顶向下)
在合并过程中,当a[i]≤a[j]时,不产生逆序对
当a[i]>a[j]时,在前半部分中比a[i]大的元素都比a[j]大,对应的逆序对数为mid-i+1,即逆序对为(a[i],a[j]),…,(a[mid],a[j])
修改Merge函数:
当a[i]>a[j]时,全局变量ans+=mid-i+1; (初始为0)
//相邻两个子表的合并
void Merge(int a[],int low,int mid,int high){
//a[low..mid]+a[mid+1..high]=a[low..high]
int* tmpa;
int i = low;
int j = mid+1;
int k = 0;
tmpa = (int*)malloc((high-low+1)*sizeof(int));
while(i<=mid&&j<=high){
if(a[i]<=a[j]){ //将第1子表中元素放入tmpa
tmpa[k] = a[i];
++i;
++k;
}
else{ //将第2子表中元素放入tmpa
tmpa[k] = a[j];
ans+=mid-i+1;
++j;
++k;
}
}
while(i<=mid){
tmpa[k] = a[i];
++i;
++k;
}
while(j<=high){
tmpa[k] = a[i];
++i;
++k;
}
for(k = 0,i = low;i<=high;++i,++k)
a[i] = tmpa[k];
free(tmpa);
}