目录
1.归并排序过程
使用归并排序实现求逆序对,那么首先得了解什么是归并排序(关于归并排序可以求逆序对,也是在做题中学会的)。
首先得了解归并排序本身的思想,再来了解使用归并排序求逆序的过程:
1.算法思想:
合并排序是采用分治策略实现对N个元素进行排序的算法,是分治法的一个典型应用和完美体现,它是一种平衡,简单的二分分治策略,计算过程分为三步:
- (1)分解:将待排序元素分成大小大致相同的两个子序列。
- (2)求解子问题:用合并排序法分别对两个子序列递归地进行排序。
- (3)合并:将排好序的有序子序列进行合并,得到符合要求的有序序列。
例如:设待排序序列A=<8,3,2,9,7,1,5,4>,采用合并排序算法对序列A进行排序。
(1)逆序对概念
假设两个元素Ai,Aj,并且i<j,但是Ai>Aj,那么(Ai,Aj)构成一对逆序对。
(2)基本思想
基本思想:归并排序是两个有序的序列(a[maxn],b[maxn])进行合并,借助一个辅助的数组aux[maxn],用来记录合并之后的序列;而合并的过程是a[i]和b[j]的值进行比较,如果a[i]的值小于等于b[j]的值,那么首先将a[i]的值放入到aux[k]中(隐含的意义就是a[i]和b[j]两个数是有序的);如果a[i]的值大于b[j]的值,那么首先将b[j]的值放入到aux[k]中(隐含的意义就是a[i]和b[j]两个数是逆序的)。
注意:现在根据这个思想画图来理解。
例如:现在对<3,6,7,4,2,1,5>进行归并排序,只画出合并的过程,分解的过程没有画出。
上图所示:根据刚才表述的思想(可能表述的不是太清楚),比如上面的第二趟归并过程中,middle=1,而left=0,right=3,可以看到元素3和4进行比较,3小于4,是顺序的,所以将3先放入aux[k]中,left下标向右移动;当6和4进行比较时,6大于了4,所以是逆序的,但是仔细看可以发现,要计算4前面到底有多少个是大于它的,直接可以使用(middle-left+1)即可算出,因为合并的每个数组都是有序的数组,所以既然6大于了4,那么如果6的后面还有数据的话,那么一定大于4,所以和4可以构成的逆序对数就是(middle-left+1).依次下面过程的合并也是同样的道理。
计算上面的逆序:count=0;
- ①第一趟4和7的比较出现逆序,1和2的比较出现逆序,所以逆序数为count=count+2;
②第二趟6和4比较出现逆序,而其他都是顺序,所以逆序数为count=count+1;
③第三趟比较,逆序数为:count=count+10;
最终的逆序数为13.
(3)算法实现
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#define MAXSIZE 11
typedef int ElemType;
int merge[MAXSIZE];
//合并两个有序子序列
int count=0;
void Merge(int merge[],int a[],int left,int right,int middle){
int i=left,j=middle+1;
int k=left;
while(i<=middle&&j<=right){
if(a[i]<=a[j]){
merge[k++]=a[i++];
}else{
merge[k++]=a[j++];
count+=middle-i+1;
}
}
while(i<=middle)merge[k++]=a[i++];
while(j<=right)merge[k++]=a[j++];
i=0;
for(i=left;i<=right;i++)a[i]=merge[i];
}
//合并排序算法
void Mergesort(int a[],int left,int right){
if(left<right){
int middle=(left+right)>>1;
Mergesort(a,left,middle);
Mergesort(a,middle+1,right);
Merge(merge,a,left,right,middle);
}
}
void display(int a[],int n){
for(int i=0;i<n;i++){
printf("%d\t",a[i]);
}
}
int main(){
int array[MAXSIZE];
int n;
for(int i=0;i<MAXSIZE;i++){
array[i]=0;
}
printf("请输入待排关键字个数: ");
scanf("%d",&n);
printf("请输入关键字: ");
for(int i=0;i<n;i++){
scanf("%d",&array[i]);
}
Mergesort(array,0,n-1);
display(array,n);
printf("\n");
printf("逆序对: %d\n",count);
return 0;
}