算法与数据结构实验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 }

 

 

 

 
posted @ 2018-10-11 20:35  王陸  阅读(1283)  评论(0编辑  收藏  举报