归并排序(逆序对的解决)

来源:互联网 发布:手机借款软件排行 编辑:程序博客网 时间:2024/06/04 23:25

 逆序对最典型的方法就是树状数组,但是还有一种方法就是归并排序

实际上归并排序的交换次数就是这个数组的逆序对个数,为什么呢?

归并排序是将数列a[l,h]分成两半a[l,mid]和a[mid+1,h]分别进行归并排序,然后再将这两半合并起来。

在合并的过程中(设l<=i<=mid,mid+1<=j<=h),当a[i]<=a[j]时,并不产生逆序数;当a[i]>a[j]时,在

前半部分比a[i]大的数都比a[j]大,将a[j]放在a[i]前面的话,逆序数要加上mid+1-i。因此,可以在归并

序中的合并过程中计算逆序数:


题:给定一个序列a[],每次只允许交换相邻两个数,最少要交换多少次才能把它变成非递降序列

/*归并排序 &计算逆序对 */ #include <iostream>  #include <string.h>  #include <stdio.h>  using namespace std;  const int N = 1005;    int a[N],tmp[N];  //全局变量定义数组(两数组相互间变换,省去引入其他数组)int ans;  //记录逆序对个数=交换次数  void Merge(int l,int m,int r)  {      int i = l;      int j = m + 1;       int k = l;     while(i <= m && j <= r)      {          if(a[i] > a[j])          {              tmp[k++] = a[j++];              ans += m - i + 1;  //将a[j]放在a[i]前面,逆序数要加上mid+1-i        }        else          {                 tmp[k++] = a[i++];          }        }       while(i <= m) tmp[k++] = a[i++];      while(j <= r) tmp[k++] = a[j++];     for(int i=l;i<=r;i++)       //将临时数组转换为原数组a.         a[i] = tmp[i];  }    void Merge_sort(int l,int r)  {         if(l < r)      {          int m = (l + r) /2;          Merge_sort(l,m);     //前段排序         Merge_sort(m+1,r);  //后段排序          Merge(l,m,r);      //前后段对比大小排序     }  }   int main()  {          int n;           scanf("%d",&n);    //输入组数据         for(int i=0;i<n;i++){            scanf("%d",&a[i]);          }         ans = 0;              Merge_sort(0,n-1);                    for(int i=0;i<n;i++)              printf("%d",a[i]);   //printf("逆序对个数为:%d"\n,ans);    return 0;  } 

原创粉丝点击