zoukankan      html  css  js  c++  java
  • 算法与数据结构实验6:逆序对(归并排序)

    Description

     

    在这个问题中,你需要分析一个对n个不同数排序的算法。该算法主要通过交换相邻数直到序列有序(升序)。比如:对输入序列

                          9 1 0 5 4

    经过一系列交换后变成有序序列

                          0 1 4 5 9
    你的任务是计算将序列变成有序最少需要经过多少次交换。

     

    Input

     

    输入包含多组测试数据。每组第一个是整数n<500,000,表示输入序列的长度,接下来是n行,每行有一个整数a[i](0≤a[i]≤999,999,999)。当n=0时表示结束。

     

    Output

     

    对每一组输入,输出该序列变成有序所需要交换的最少的次数。

     

    Sample Input

    5
    9
    1
    0
    5
    4
    3
    1
    2
    3
    0
    

    Sample Output

    6
    0

    解题思路:看到这个题按照题目意思“要通过交换相邻数直到序列有序(升序)”这是什么?冒泡排序?虽然冒泡排序就是基于这种思想,可是O(n^2)的时间
    复杂度并不允许我这么搞,那该怎么办?

    模拟原始做法:
    对于数组:4 8 2 7 5 6 1 3
    1 4 8 2 7 5 6 3------>6次
    1 2 4 8 7 5 6 3------>2次
    1 2 3 4 8 7 5 6------>5次
    1 2 3 4 5 8 7 6------>2次
    1 2 3 4 5 6 8 7------>2次
    1 2 3 4 5 6 7 8------>1次

    在模拟过程中,我们发现每次都是找到一个最小的然后移到最前面,但是除了这个最小的,其他数的相对次序并没有改变,所以我们可以将原始做法换一种表述方式:

    找到最小的,统计它前面有多少个数比它大,然后加入结果,将这个最小的删去。如此反复。

    这时我们就发现,其实原题就是求数列的逆序对的个数!归并排序,线段树,树状数组搞起来!!!!

    我之前写过的关于逆序数求法的博客https://www.cnblogs.com/wkfvawl/p/9512861.html

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 #define maxn 500010
     5 #define ll long long int
     6 using namespace std;
     7 ll a[maxn];
     8 ll temp[maxn];
     9 ll sum;
    10 void Merge(int l,int r,int m)
    11 {
    12     int i=l;
    13     int j = m + 1;
    14     int k = l;
    15     while(i<=m&&j<=r)
    16     {
    17         if(a[i]>a[j])
    18         {
    19             sum+=m-i+1;///剩下的没有进入临时空间的元素的个数
    20             temp[k++]=a[j++];
    21         }
    22         else
    23         {
    24             temp[k++]=a[i++];
    25         }
    26     }
    27     while(i<=m)///将剩余的元素存到数组中
    28     {
    29         temp[k++]=a[i++];
    30     }
    31     while(j<=r)
    32     {
    33         temp[k++]=a[j++];
    34     }
    35     for(i=l; i<=r; i++)
    36     {
    37         a[i]=temp[i];
    38     }
    39 }
    40 void mergesort(int l,int r)
    41 {
    42     if(l<r)
    43     {
    44         int m = (l + r) / 2;
    45         mergesort(l,m);///左二分排序
    46         mergesort(m+1,r);///右二分排序
    47         Merge(l,r,m);///合并两个升序数组
    48     }
    49 }
    50 int main()
    51 {
    52     int n,i;
    53     while(scanf("%d",&n)!=EOF)
    54     {
    55         if(n==0)
    56         {
    57             break;
    58         }
    59         for(i=0; i<n; i++)
    60         {
    61             scanf("%lld",&a[i]);
    62         }
    63         sum=0;
    64         mergesort(0,n-1);
    65         printf("%lld ",sum);
    66     }
    67     return 0;
    68 }
     
  • 相关阅读:
    极光推送SDK通过泰尔终端实验室检测,符合统一推送接口标准
    极光小课堂|手把手教你做接口测试
    一键登录怎么在iOS端实现?这篇文章教会你!
    一键登录已成大势所趋,Android端操作指南来啦!
    极光一键登录:更快捷、安全的登录认证方式,简单集成即可实现
    跨浏览器问题的五种解决方案
    Laravel 搭建 Composer 包,实现配置 Config、门面 Facade、服务 Service、发布到 Packagist
    How to Install ClamAV on Ubuntu 20.04 and Scan for Vulnerabilities
    单点登录(SSO)看这一篇就够了
    一口气说出 OAuth2.0 的四种授权方式
  • 原文地址:https://www.cnblogs.com/wkfvawl/p/9774900.html
Copyright © 2011-2022 走看看