归并排序(c语言)————求逆序数

”归并“就是合并的意思,归并排序就将两个或两个以上的有序的序列合并再重新排序

1.定义

归并排序(Merging sort)就是把初始序列分为有n个排序好的子序列,每个子序列的长度为1,然后两两合并排序,如此重复,直到合并为长度为n的有序序列为止(2路归并函数)

实现归并排序可以使用递归和循环两种方法下面是递归运用到的定义函数

归并排序的应用求逆序数
题目描述

在一个排列中,如果一对数的前后位置与大小顺序相反,即前面的数大于后面的数,那么它们就称为一个逆序。一个排列中逆序的总数就称为这个排列的逆序数。

现在,给你一个N个元素的序列,请你判断出它的逆序数是多少。

比如 1 3 2 的逆序数就是1。

输入

第一行输入一个整数T表示测试数据的组数(1<=T<=5)
每组测试数据的每一行是一个整数N表示数列中共有N个元素(2〈=N〈=100000)
随后的一行共有N个整数Ai(0<=Ai<1000000000),表示数列中的所有元素。

数据保证在多组测试数据中,多于10万个数的测试数据最多只有一组。

输出

输出该数列的逆序数

样例输入 
2
2
1 1
3
1 3 2
样例输出 
0
1

 解题思路

通过归并排序求逆序数,sum+=mid+i-1,当时这一步看了好久都没理解为什么这样表示最后还是通过图才理解的,我们知道归并排序每次合并的时候用到了类似双指针的思想, i ,j 最开始分别指向数组的开头(left)和中间(mid+1),每次比较b[i],b[j],将小的值先放入如果b[j]>b[i],那么先放入b[j],因为b数组中 i 到 mid 是排序好的,j 到 n 是排序好的b[j]<b[i],那b[j]自然也就小于b数组中i到mid的元素,这些b[j]与b[i]和i到mid的的元素都组成逆序数,如下图第三趟归并此时b[i]==3,b[j]==1,1与后面的     3,4,6,7都组成逆序数此时统计个数就可以写成sum+=mid+i-1。

AC代码

#include <stdio.h>
long long a[100011], b[100011];//a数组为要排序的代码,b数组为中间代码
long long n, f = 0;//f用于统计逆序数个数
void nb(long long x, long long y) //归并排序核心代码
{
    if (x >= y) return;//当分治只有一个元素时结束
    long long mid = (x + y) / 2, i, j;
    //分为两部分
    nb(x, mid);
    nb(mid + 1, y);
    int cnt = 0;
    for (i = x, j = mid + 1; i <= mid && j <= y;) //合并部分  双指针思想
    {
        if (a[i] <= a[j]) 
        {
            b[++cnt] = a[i++];
        }
        else
        {
            b[++cnt] = a[j++];
            f += mid - i + 1;//统计逆序数
        }
    }
    while (i <= mid)
        b[++cnt] = a[i++];
    while (j <= y)
        b[++cnt] = a[j++];
    for (int i = 1; i <= cnt; i++)//排序完后赋值给a数组
        a[i + x - 1] = b[i];
}
int main()
{
    int t;
    scanf("%d", &t);//输入测试组数
    while (t--)
    {
        f = 0;//清零上次数据
        scanf("%lld", &n);
        for (int i = 1; i <= n; i++)
            scanf("%lld", &a[i]);
        nb(1, n);//调用函数
        printf("%lld\n", f);//打印逆序数
    }
    return 0;
}

  • 17
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

3分人生

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值