zoukankan      html  css  js  c++  java
  • 浅谈归并排序

    本文已彻底 沦为 变成博主的习题册,清转头阅读其他文章哦~啾咪~


    参考了文章:https://blog.csdn.net/qq_41550842/article/details/81215935

    归并排序的理解

    归并排序

    (图源见水印)

    归并排序,可以看这个网站的动图理解:https://visualgo.net/zh/sorting?slide=10-2

    归并排序是分治算法的一种体现,分治解题的一般步骤是:

    1. 划分步骤:将大的原始问题划分成较小的子问题并递归地解决较小的子问题,
    2. 解决步骤:结合较小的子问题的结果来产生较大的原始问题的结果。

    而归并排序的步骤可以细化为:

    1. 划分问题:把序列分成元素个数尽量相等的两半
    2. 递归求解:把两半元素分别排序
    3. 合并问题:把两个有序表合并为一个

    在合并两边已排好的元素时,因为两个序列都具有不下降性,所以只需要比较两个序列里最小的元素就可以。 

    对于实现,一般需要一个辅助数组;

    #include<bits/stdc++.h>
    using namespace std;
    const int N =  1000005;
    int a[N] ,b[N];//b为辅助数组
    void merge_sort(int l , int r)
    {
        if(l < r){ //如果整个区间中元素个数大于1,则继续分割
            int mid = (l + r) >> 2 ;  //位运算提高速度
            int i = l; //辅助数组的下标
            int p = l , q = mid+1;
            merge_sort(l,mid);
            merge_sort(mid+1 ,r);
            while(p<=mid || q<=r){//左右两部分只要有一部分不为空
                if(q>r || (p<=mid && a[p]<=a[q]))//右边空了或者右边的数更大一点,就把左边的这个数放到前面一点点,(从左半数组复制到辅助数组)
                    b[i++] = a[p++];
                else b[i++] = a[q++];//从右半数组复制到辅助数组
            }
            for(i = l ; i <= r; i++)//将b中排好序的元素复制到a中
                a[i] = b[i];
        }
    }
    int main()
    {
         int n;
         scanf("%d",&n);
         for(int i = 1 ; i <= n; i ++)  cin >> a[i];
         merge_sort(1 , n);
         for(int i = 1; i <= n; i++) cout << a[i] << " ";
         return 0;
    }
    View Code

    归并排序的应用

    1.求逆序对

    (听说可以用树状数组,然鹅小蒟蒻还没有学,学了以后再补一个叭qwq)

    在比较的时候考虑:如果左边最小的数都比右边这个数大,那么左边剩余的所有数都会比右边这个数大 

    #include<bits/stdc++.h>
    using namespace std;
    #define N 1000005
    int a[N] ,b[N]; 
    long long cnt;
    void merge_sort(int l , int r)
    {
        if(l < r){
            int mid = (l + r) / 2 ;
            int i = l; 
            int p = l , q = mid+1;
            merge_sort(l , mid);
            merge_sort(mid+1 , r);
            while(p<=mid || q<=r){
                if(q > r || (p <= mid && a[p] <= a[q])) b[i++] = a[p++];
                else{
                    b[i++] = a[q++];
                    cnt += mid -p +1;  //将逆序对的个数累加起来
                }
            }
            for(i = l ; i <= r; i++) a[i] = b[i];
        }
    }
    int main()
    {
        int n;
        scanf("%d",&n);
        for(int i = 1 ; i <= n; i ++) cin >> a[i];
        cnt = 0;
        merge_sort(1 , n);
        printf("%lld",cnt);
        return 0;
    }
     
    求逆序对

    [求逆序对·进阶版] noip2013火柴排队

    //火柴 
    #include<bits/stdc++.h>
    const int N = 200005;
    const int mod = 99999997;
    struct node{
        int x,p;
    };
    node a[N],b[N];
    int n,c[N],f[N],ans;
    int cmp(node a,node b){ return a.x < b.x;}
    
    void m_sort(int l,int r){
        if(l == r) return ;
        int mid = (l + r)/ 2;  //这个地方不可以改哦 
        int i = l, j = mid + 1,k = l;
        m_sort(l,mid);
        m_sort(mid+1,r);
        while(i <= mid && j <= r){
            if(c[i] <= c[j]) f[k++] = c[i++];
            else {
                f[k++] = c[j++];
                ans += mid - i + 1;
                ans %= mod;
            }
        }
        while(i <= mid) f[k++] = c[i++];
        while(j <= r ) f[k++] = c[j++];
        for(int i = l; i <= r; i++) c[i] = f[i];
    }
    signed main(){
        scanf("%d",&n);
        for(int i = 1; i <= n; i++) {
          scanf("%d",&a[i].x);
           a[i].p =i;    
        }
        for(int i = 1; i <= n; i++) {
          scanf("%d",&b[i].x);
          b[i].p =i;    
        }
        std::sort(a+1,a+n+1,cmp);
        std::sort(b+1,b+n+1,cmp);
        for(int i = 1; i <= n; i++) c[a[i].p] = b[i].p;
        m_sort(1,n); 
        printf("%d",ans);
        return 0;
    }
    火柴排队

    2.只涉及相邻元素的排序

    这种情况下快排会浪费很多时间,而归并正是解决这种问题的利器。

    e.g. NOIP2011瑞士轮

    #include<iostream> 
    #include<algorithm>    
    using namespace std; 
    #define fr(i,n)  for(register int i = 1; i <= n; ++i) 
    int n,r,q;  
    const int N = 200500;
    int a[N],win[N],lose[N],c[N],w[N];   
    int tot;
    bool cmp(int x,int y)  {  
      if(c[x]==c[y])   return x<y;
      return c[x]>c[y];
    }  
    void merge(){
        int l = 1, r = 1, k = 0;
        while(l <= tot && r <= tot) {
            if(cmp(win[l],lose[r]))  a[++k] = win[l++];
            else a[++k] = lose[r++];
        }
        while(l <= tot) a[++k] = win[l++];
        while(r <= tot) a[++k] = lose[r++];
    }
    int main(){
        scanf("%d%d%d",&n,&r,&q);
        n = n * 2;
        fr(i,n) a[i] = i;
        fr(i,n) scanf("%d",c+i);
        fr(i,n) scanf("%d",w+i);
        sort(a+1,a+1+n,cmp);  //a[i]记录的是排名为i的选手是哪位 
        while(r--){
            tot = 0;
            for(register int i = 1; i <= n; i+=2){ //跳二是排名紧靠着的两位选手一起比赛 
                if(w[a[i]] > w[a[i+1]]){
                  win[++tot] = a[i];   //这两行   记录了赢和输这一场的分别是哪个选手 
                  lose[tot] = a[i+1];
                  c[a[i]]++;    //分数++ 
                }
                else{
                  win[++tot] = a[i+1];
                  lose[tot] = a[i];
                  c[a[i+1]]++;    
                }
            }
            merge();
        }
        printf("%d
    ",a[q]);
        return 0;
    }
    View Code
    #include<iostream> 
    #include<algorithm>    
    using namespace std; 
    #define fr(i,n)  for(register int i = 1; i <= n; ++i) 
    int n,r,q;  
    const int N = 200500;
    int a[N],win[N],lose[N],c[N],w[N];   
    int tot;
    bool cmp(int x,int y)  {  
      if(c[x]==c[y])   return x<y;
      return c[x]>c[y];
    }  
    void merge(){
        int l = 1, r = 1, k = 0;
        while(l <= tot && r <= tot) {
            if(cmp(win[l],lose[r]))  a[++k] = win[l++];
            else a[++k] = lose[r++];
        }
        while(l <= tot) a[++k] = win[l++];
        while(r <= tot) a[++k] = lose[r++];
    }
    int main(){
        scanf("%d%d%d",&n,&r,&q);
        n = n * 2;
        fr(i,n) a[i] = i;
        fr(i,n) scanf("%d",c+i);
        fr(i,n) scanf("%d",w+i);
        sort(a+1,a+1+n,cmp);
        while(r--){
            tot = 0;
            for(register int i = 1; i <= n; i+=2){
                if(w[a[i]] > w[a[i+1]]){
                  win[++tot] = a[i];
                  lose[tot] = a[i+1];
                  c[a[i]]++;    
                }
                else{
                  win[++tot] = a[i+1];
                  lose[tot] = a[i];
                  c[a[i+1]]++;    
                }
            }
            merge();
        }
        printf("%d
    ",a[q]);
        retur
    满堂花醉三千客,一剑霜寒十四州
  • 相关阅读:
    dagScheduler
    elasticsearch映射
    elasticsearch数据结构
    spring boot 整合 elasticsearch 5.x
    spark快速开发之scala基础之5高阶函数,偏函数,闭包
    Halcon学习笔记2
    HALCON算子1
    Halcon学习笔记1
    ML-学习提纲2
    ML-学习提纲1
  • 原文地址:https://www.cnblogs.com/phemiku/p/11406038.html
Copyright © 2011-2022 走看看