归并排序

归并排序

1.归并排序是利用的分治的策略进行的排序,用的二分,每次都分成两部分,这两部分分别有序,在合并为一个整体有序。
2.归并排序是稳定排序

归并排序分的部分采用递归的形式:

void mysort(int L,int R){
    if(L>=R) return ;
    int mid=(L+R)>>1;
    mysort(L,mid);//下面两步就是二分
    mysort(mid+1,R);
    bin(L,R,mid);// 归并操作
}

代码看上去并不复杂,关键在于合并部分:

void bin(int L,int R,int mid){
    int i=L,j=mid+1;
    int k=L;
    while(i<=mid&&j<=R){//相当于两个指针,分别指向两边的头部(两边皆为有序的),所以当那一边更小,就把他加入到b数组中然后该指针++
        if(a[i]<a[j]){
            b[k++]=a[i++];
        }
        else{
            ans+=mid-i+1;//求逆序对
            b[k++]=a[j++];
        }
    }
    while(i<=mid) b[k++]=a[i++];
    while(j<=R) b[k++]=a[j++];
    for(int t=L;t<=R;t++) a[t]=b[t];
}

归并排序的一个小运用就是求逆序对 给一道例题:
链接:https://ac.nowcoder.com/acm/problem/15163
来源:牛客网

题目描述
在一个排列中,如果一对数的前后位置与大小顺序相反,即前面的数大于后面的数,那么它们就称为一个逆序。一个排列中逆序的总数就称为这个排列的逆序数。比如一个序列为4 5 1 3 2, 那么这个序列的逆序数为7,逆序对分别为(4, 1), (4, 3), (4, 2), (5, 1), (5, 3), (5, 2),(3, 2)。
输入描述:

第一行有一个整数n(1 <= n <= 100000), 然后第二行跟着n个整数,对于第i个数a[i],(0 <= a[i] <= 100000)。

输出描述:

输出这个序列中的逆序数

示例1
输入
5
4 5 1 3 2

输出

7

求逆序对:你观察归并排序的归并部分

while(i<=mid&&j<=R){//相当于两个指针,分别指向两边的头部(两边皆为有序的),所以当那一边更小,就把他加入到b数组中然后该指针++
        if(a[i]<a[j]){
            b[k++]=a[i++];
        }
        else{
            b[k++]=a[j++];
        }
    }

当右边的部分当前位置更小时,那现在是不是右边部分当前指针指的位置的右边到mid都比右边当前的大。所以
逆序对的值就只需在这时加上一个mid-i+1就完了

完整代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=1e5+5;
int a[N],b[N];//b为归并排序的辅助数组
ll ans=0;
void bin(int L,int R,int mid){
    int i=L,j=mid+1;
    int k=L;
    while(i<=mid&&j<=R){//相当于两个指针,分别指向两边的头部(两边皆为有序的),所以当那一边更小,就把他加入到b数组中然后该指针++
        if(a[i]<a[j]){
            b[k++]=a[i++];
        }
        else{
            ans+=mid-i+1;//求逆序对
            b[k++]=a[j++];
        }
    }
    while(i<=mid) b[k++]=a[i++];
    while(j<=R) b[k++]=a[j++];
    for(int t=L;t<=R;t++) a[t]=b[t];
}
void mysort(int L,int R){
    if(L>=R) return ;
    int mid=(L+R)>>1;
    mysort(L,mid);//下面两步就是二分
    mysort(mid+1,R);
    bin(L,R,mid);// 归并操作
}
int main(){
    int n;
    cin>>n;
    for(int i=0;i<n;i++) cin>>a[i];
    mysort(0,n-1);
    cout<<ans<<endl;
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值