【33】利用归并排序求逆序数对

 

题目:利用归并排序求解一个数组中的逆序数对

 

分析:

1. 什么是逆序数对,例如给定数组{7, 5, 6, 4},对于每个数num,如果num之前有多少个数大于num则说明num这个数构成逆序数对有多少个

    7有0个,5有1个,6有1个,4有三个,因此数组中总的逆序数对为5。

 

2. 怎么利用归并排序来求逆序数对呢?

   (1)假设数组为{7, 5, 6, 4}

   (2)归并排序的递归树如下

       

   (3)求逆序数对是在合并左右两个子序列的时候。在merge函数中,左右子序列都是各自有序。

            在合并两个子序列的时候我们是从前往后枚举两个子序列,每次求两个数中的最小值存放到另一个数组中。

            假设此时左序列数为arr[i],有序列为arr[j]。

            如果arr[i] > arr[j],则可以知道左序列中从i开始到结束的所有元素都和arr[j]构成逆序数对。

            如果arr[i] <= arr[j]则无法构成逆序数对。

   (4)根据第三点,我们可以对数组{7,5,6,4}进行验证

           合并第三层:7 > 5逆序数加1;6 > 4逆序数加1。合并完第三层为(5 7) 和 (4 6)

           合并第二层:5 > 4逆序数加2;7 > 4逆序数加1。合并完第二层为(4 5 6 7)

           第一层不用合并,所以总的逆序数对为5。

 

3. 代码

 

#include<iostream>
#include<algorithm>
using namespace std;

const int N = 1010;
int ans;

//合并左右子序列
void Merge(int *arrNum, int l, int mid, int r){
    //数据不合法 
	if(arrNum == NULL || l > r){
       return;
    }
    int i = l;
	int j = mid+1;
	int pos = l;
	int tmpArr[N]; 
	//枚举
	while((i <= mid) && (j <= r)){
        if(arrNum[i] <= arrNum[j]){
            tmpArr[pos++] = arrNum[i++];
        }
        else{
            ans += (mid-i+1);//加上逆序数对
			tmpArr[pos++] = arrNum[j++]; 
		}
	} 
	//剩下的直接插入数组末尾
	while(i <= mid){
        tmpArr[pos++] = arrNum[i++];
	} 
	while(j <= r){
        tmpArr[pos++] = arrNum[j++];
	} 
	//复制回新的数组 
	for(int k = l; k <= r; k++){
        arrNum[k] = tmpArr[k];
	}
} 

//求逆序数对 
int GetReverseNumber(int *arrNum, int l, int r){
	//数据不合法 
	if(arrNum == NULL || l >= r){
        return 0;
    }
    int mid = (l+r)>>1;
    GetReverseNumber(arrNum, l, mid);
    GetReverseNumber(arrNum, mid+1, r);
    Merge(arrNum, l, mid, r);
}
 
int main(){ 
    int arrNum[] = {7,5,6,4};
    //求逆序数对
    ans = 0;
    GetReverseNumber(arrNum, 0, 3);
    cout<<ans<<endl;
    getchar();
    return 0;
}
/*
输出
5 
*/

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值