数据结构实验之排序五:归并求逆序数

数据结构实验之排序五:归并求逆序数

Time Limit: 50MS Memory Limit: 65536KB
Problem Description

对于数列a1,a2,a3…中的任意两个数ai,aj (i < j),如果ai > aj,那么我们就说这两个数构成了一个逆序对;在一个数列中逆序对的总数称之为逆序数,如数列 1 6 3 7 2 4 9中,(6,4)是一个逆序对,同样还有(3,2),(7,4),(6,2),(6,3)等等,你的任务是对给定的数列求出数列的逆序数。

Input

输入数据N(N <= 100000)表示数列中元素的个数,随后输入N个正整数,数字间以空格间隔。

 

Output

输出逆序数。

Example Input
10
10 9 8 7 6 5 4 3 2 1
Example Output
45

#include <bits/stdc++.h>  
using namespace std;  
long long num=0;  
  
void merg(int a[],int l,int mid,int r)   //归并  
{  
    int i=l,j=mid+1,k=0;  //i为第一段开始,j为第二段开始  
    int *b=(int *)malloc((r-l+1)*sizeof(int));  //动态数组存储临时合并序列  
    while(i<=mid&&j<=r) //读取两段序列  
    {  
        if(a[i]<=a[j])    //将两段中小的存入b[]  
            b[k++]=a[i++];  
        else  
        {  
            b[k++]=a[j++];  
            num+=(mid-i+1);  //若a[i]>a[j] 则之后的(mid-i+1)个数都大于a[j]  
        }  
    }  
    while(i<=mid) b[k++]=a[i++];  //若第一段没完,并到b[]  
    while(j<=r) b[k++]=a[j++];     //若第二段没完,并到b[]  
    for(k=0,i=l; i<=r; i++,k++)     //将b[]复制到a[]  
        a[i]=b[k];  
}  
  
void mergesort(int a[],int l,int r)    //分解  
{  
    int mid;  
    if(l<r)  
    {  
        mid=(l+r)/2;  
        mergesort(a,l,mid);  
        mergesort(a,mid+1,r);  
        merg(a,l,mid,r);  
    }  
}  
  
int a[100010];  
int main()  
{  
    int n,i;  
    scanf("%d",&n);  
    for(i=0; i<n; i++)  
        scanf("%d",&a[i]);  
    mergesort(a,0,n-1);  
    printf("%lld\n",num);  
    return 0;  
} 

归并排序的基本思想
将待排序序列R[0...n-1]看成是n个长度为1的有序序列,将相邻的有序表成对归并,得到n/2个长度为2的有序表;
将这些有序序列再次归并,得到n/4个长度为4的有序序列;如此反复进行下去,最后得到一个长度为n的有序序列。
综上可知:
归并排序其实要做两件事:
(1)“分解”——将序列每次折半划分。
(2)“合并”——将划分后的序列段两两合并后排序。
 
我们先来考虑第二步,如何合并?
在每次合并过程中,都是对两个有序的序列段进行合并,然后排序。
这两个有序序列段分别为 R[low, mid] 和 R[mid+1, high]。
先将他们合并到一个局部的暂存数组R2中,带合并完成后再将R2复制回R中。
为了方便描述,我们称 R[low, mid] 第一段,R[mid+1, high] 为第二段。
每次从两个段中取出一个记录进行关键字的比较,将较小者放入R2中。最后将各段中余下的部分直接复制到R2中。
经过这样的过程,R2已经是一个有序的序列,再将其复制回R中,一次合并排序就完成

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值