归并排序与逆序对


归并排序
基本思想
归并排序是用分治的思想。将大问题分成许多小问题。在每层递归上有三个步骤

具体演示

将数组一分为二,直到分割到只剩一个元素的时候开始向上递归,可以发现在合并数组之前,两个子数组都是有序的

代码模板
#include
using namespace std;
const int N=1e6+10;
int tmp[N];
void merge_sort(int q[],int l,int r){
   //递归函数的出口。当切割到只剩一个元素的时候向上递归
   if(l>=r)return;
   //移位的优先级没有加法高,相当于(l+r)/2
    int mid=l+r>>1;
   //对左半边处理
   merge_sort(q,l,mid);
   //对右半边处理
   merge_sort(q,mid+1,r);
   //处理完成两部分数组 l-mid整体有序 mid+1到r整体有序,通过临时数组tmp对两个数组进行操作。定义一个左指针和右指针来对比元素的大小,k为tmp的长度也就是l-r的元素个数
   int i=l,j=mid+1,k=0;
   //当两个数组都有剩余元素进行循环如果左边数组小,将左边数组元素放入tmp,指针向后移动一位,数组长度k++,反之数组右边元素放入tmp,指针向后移动一位,数组长度++;
   while(i<=mid&&j<=r){
       if(q[i]        else tmp[k++]=q[j++];
  }
   //如果上面的循环结束说明有一个数组已经没有的剩余元素。那么另外的数组的剩余元素的第一个一定大于tmp[k],只需将剩余数组的元素平移到tmp即可
   while(i<=mid)tmp[k++]=q[i++];
   while(j<=r)tmp[k++]=q[j++];
   //对tmp进行遍历。将tmp的元素平移到目标数组的l-r
   for(int i=l,j=0;j        q[i]=tmp[j];
  }
}
int main(){
   int q[N],n;
   cin>>n;
   for(int i=0;i>q[i];
   merge_sort(q,0,n-1);
   for(int i=0;i }
逆序对的数量
给定一个长度为 n 的整数数列,请你计算数列中的逆序对的数量。 逆序对的定义如下:对于数列的第 i 个和第 j 个元素,如果满足 ia[j] ,则其为一个逆序对;否则不是。

输入格式
第一行包含整数 n,表示数列的长度。 第二行包含 n 个整数,表示整个数列。

输出格式
输出一个整数,表示逆序对的个数。

数据范围
1 ≤ n ≤ 100000 , 1≤n≤100000 , 1n100000

数列中的元素的取值范围[1,1e9]

输入样例
6
2 3 4 5 6 1
输出样例
5
题目的意思是数组前面的数比后面的大就能构成一对逆序对[2,1],[3,1],[4,1],[5,1],[6,1]正好五对。可以是用递归的方法处理这个问题。将可能出现的逆序对抽象成三种情况

三种情况组成的逆序对相加就是数组的全部逆序对,对数组的左右两边排序,对第三种条件的计算会方便很多。例如q[L]>q[R],那么q[L]-q[MID]就可以和q[R]组成逆序对。因为两个数组都是有序的。那么q[L]之后的元素一定都大于等于q[L]。在加上q[L]>q[R]所以L后面的元素包括L都可以和下标为R的元素构成逆序对。所以采用归并排序解决。归并的特点正好完全符合这个问题。其实具体拆解,只存在第三种情况,第二种和第一种情况是由第三种情况计算得出的。

算法模板
#include
using namespace std;
const int N=1e6+10;
int tmp[N];
//数据范围过大 使用longlong类型
long long merge_sort(int q[],int l,int r){
   if(l>=r) return 0;
   int mid=l+r>>1;
   //将第三种情况的值转换为第一第二种
  long long ans = merge_sort(q,l,mid)+merge_sort(q,mid+1,r);
    long i=l,j=mid+1,k=0;
   while(i<=mid&&j<=r){
   
       if(q[i]<=q[j])tmp[k++]=q[i++];
       else{
           tmp[k++]=q[j++];
           //mid-i+1为i-mid的元素个数,都能与q[j]组成逆序对
           ans=ans+mid-i+1;
      }
  }
   while(i<=mid)tmp[k++]=q[i++];
   while(j<=r) tmp[k++]=q[j++];
   // for(int i=0;i<6;i++)cout<    // cout<    for(int i=l,j=0;j      
       q[i]=tmp[j];
}
return ans;
}
int main(){
    int q[N],n;
   cin>>n;
   for(int i=0;i>q[i];
   long long k=merge_sort(q,0,n-1);
   cout<      
  return 0;
}

你可能感兴趣的:(算法,排序算法,数据结构)