• 快速排序 && 归并排序


    模板:

    //快速排序
    #include <iostream>
    using namespace std;
    const int N = 100010;
    int a[N];
    void qsort(int l, int r)
    {
        if(l >= r) return;
        int i = l - 1, j = r + 1, x = a[(l + r + 1) >> 1];
        while (i < j) {
            do i++;while(a[i] < x);
            do j--;while(a[j] > x);
            if(i < j) swap(a[i], a[j]);
        }
        qsort(l,i - 1);qsort(i,r);
    }
    int main()
    {
        int n;
        cin>>n;
        for (int i = 0; i<n; i++) {
            cin>>a[i];
        }
        qsort(0,n-1);
        for (int i = 0; i<n; i++) {
            cout<<a[i]<<" ";
        }
    }
    do i++;while(a[i] < x); 
    do j--;while(a[j] > x);
    这里也可以写成while(a[++i] < x);while(a[--j] > x);
    每次选择的数在快排之后都是左边小于等于它,右边大于等于它,所以递归循环的时候要根据所选的x来相应的变化:
    1、若qsort(l,i -1);qsort(i,r), 那么所选择的中间变量就不能是x = a[l]或x = a[l + r >> 1],而应该是x = a[l + r + 1 >> 1]或x = a[r];
    2、若qsort(l,j);qsort(j + 1,r);那么所选择的中间变量就不能是x = a[r]或 x = a[l + r + 1 >> 1], 而应该是x = a[l + r >> 1]或 x = a[l];
    可以用比如3 5 1 4 2来模拟举例,可以选择第一个数a[l]、中间的数a[l + r >> 1]、右边的数a[r]来模拟,可以确定正确的策略都是在每次外层while循环结束后,qsort(l,j)都是小于等于x的数,qsort(j+1,r)都是大于等于x的数。
    然后递归排序即可。
    然后可以再选在只有两个数的数列:1 2来进行模拟,确定上面qsort和中间比较数x的选择策略。
    第k个数:
    //快速排序
    #include <iostream>
    using namespace std;
    const int N = 100010;
    int a[N];
    int qsort(int l, int r, int k)
    {
        if(l >= r) return a[l];
        int i = l - 1, j = r + 1, x = a[l];
        while (i < j) {
            do i++;while(a[i] < x);
            do j--;while(a[j] > x);
            if(i < j) swap(a[i], a[j]);
        }
        int t = j - l + 1;
        if(k <= t) return qsort(l,j,k);
        else return qsort(j + 1, r, k-t);
    }
    int main()
    {
        int n,k;
        cin>>n>>k;
        for (int i = 0; i<n; i++)
            cin>>a[i];
    
        cout<<qsort(0,n-1,k)<<endl;
        
    }

     归并排序(求逆序对的个数):

    #include <iostream>
    using namespace std;
    const int N = 100000;
    #define LL long long
    int a[N],tmp[N];
    LL qsort(int l, int r)
    {
        if(l >= r) return 0;
        int mid = (l + r) >> 1;
        LL x = qsort(l,mid), y = qsort(mid+1,r);
        LL res = x + y;
        int i = l, j = mid + 1, k = 0;
        while(i <= mid && j <= r)
        {
            if(a[i] <= a[j]) tmp[k++] = a[i++];
            else
            {
                tmp[k++] = a[j++];
                int t = mid - i + 1;
                res += t;
            }
        }
        while(i <= mid) tmp[k++] = a[i++];
        while(j <= r) tmp[k++] = a[j++];
        for(int i = l,j = 0;i <= r;i++,j++)
            a[i] = tmp[j];
        return res;
    }
    int main()
    {
        int n;
        cin>>n;
        for(int i = 0;i<n;i++) cin>>a[i];
        cout<<qsort(0,n-1)<<endl;
    }

    最后答案res = qsort(l,mid) + qsort(mid + 1, r); 

    res += mid - i + 1;

    这里虽然看起来是加了两次,但实际上最后都会转化成下面的部分。

    因为最后数列被递归划分都是成为个数为一个的序列,然后当i == j的时候return 0递归栈返回,进行归并的时候,就进入到while循环里面进行判断,无论一开始的左半部分和右半部分,最后归并的时候都是从1、2、4、8来归并起来的,所以虽然划分了三部分:逆序对在左半部分、在右半部分、分散在左右半边,但归并的时候都是涵盖在res += mid - i + 1里面来了。

  • 相关阅读:
    nginx reload 与 restart 的区别
    求解一个数n的阶乘(递归求解 与 循环求解)
    类的加载机制
    JVM基础知识
    File类中常用的方法以及搜索路径下的包含指定词的文件
    给定10万数据,数据范围[0~1000),统计出现次数最多的10个数据,并打印出现次数
    TreeMap以及自定义排序的Comparable和Comparator的实现
    HashTable与LinkedHashMap
    HashMap
    Map接口
  • 原文地址:https://www.cnblogs.com/longxue1991/p/12603917.html
Copyright © 2020-2023  润新知