• 快速排序模板


    快排核心问题

    1. 快排最关键的位置就是 关键点的选取和递归排序时子区间端点的选择,可以简记为

    关键点选左端点,子区间端点要看右指针
    关键点选右端点,子区间端点要看左指针
    关键点选中间,子区间端点随意选
    原因可以理解为处理特殊情况(特例见代码)

    1. 在分子区间端点时,为什么是([l, j], [j + 1, r])([l, i - 1], [i, r])
      首先要明确我们的目标是保证关键点左侧都是 <= 它的数,关键点右侧都是 >= 它的数。
      我们看j点,最终指向的应该是 <= 关键点的数据,由于无法区分是小于还是等于,所以直接分到左半边,所以是([l, j]),自然就对应了([j + 1, r])
      同理可得(i)这种划分方法的原因
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    
    const int N = 1e6 + 10;
    
    int n;
    int a[N];
    
    void quick_sort(int a[], int l, int r)
    {
        if (l >= r) return ;
        
        int x = a[l + r >> 1], i = l - 1, j = r + 1;
        
        while(i < j)
        {
            while (a[++ i] < x); // 按照实际思路,x左侧应该为<=x的值,但是这么做相当于是<x的值,这样说就说不通了,但是如果写为<=假设对于14253是无法得到正确结果的,这里的边界情况较多,不做深入追究
            while (a[-- j] > x);
            if (i < j) swap(a[i], a[j]);
        }
        
        // 测试x的选取的数据可以是:
        // 2
        // 1 2
        // x = a[l]; || x = a[l + r >> 1];
        quick_sort(a, l, j);
        quick_sort(a, j + 1, r);
        // x = a[r]; || x = a[l + r >> 1];
        // quick_sort(a, l, i - 1);
        // quick_sort(a, i, r);
    }
    int main()
    {
        cin >> n;
        for (int i = 0; i < n; ++ i) cin >> a[i];
        
        quick_sort(a, 0, n - 1);
        
        for (int i = 0; i < n; ++ i) cout << a[i] << " ";
        
        return 0;
    }
    

    快速排序引申出的快速选择算法

    该算法能够在(O(n))的时间复杂度内找到无序序列中第(k)小的数

    问题描述

    给定一个长度为(n)的整数数列,以及一个整数(k),请用快速选择算法求出数列从小到大排序后的第(k)个数

    问题分析

    已知一个无序序列,我们选定(x)作为分界值,快速排序第一轮之后,序列被分为两半部分,左半边所有数值(<=x),设长度为(sl);右半边所有数值(>=x),设长度为(sr)
    假设我们想要找得是第(k)小的数,如果(k<=sl),说明待求值位于左半边,如果(k>sl),说明待求值位于右半边。根据该性质,我们只需要递归对应区间进行快速排序,最终即可找到第(k)小的数
    第1轮快速排序运算次数为(n),之后每次快排的期望运算次数依次减半,所以(时间复杂度 = n + frac{n}{2} + frac{n}{4} + ... = n(1 + frac{1}{2} + frac{1}{4} + ...) <= 2n),所以时间复杂度为(O(n))

    代码实现-手写快速选择

    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    
    const int N = 100010;
    
    int n, k;
    int a[N];
    
    int quick_sort(int a[], int l, int r, int k)
    {
        if (l >= r) return a[l];
        
        int x = a[l + r >> 1], i = l - 1, j = r + 1;
        while (i < j)
        {
            while (a[++ i] < x);
            while (a[-- j] > x);
            if (i < j) swap(a[i], a[j]);
        }
        
        int sl = j - l + 1;
        if (k <= sl) return quick_sort(a, l, j, k);
        return quick_sort(a, j + 1, r, k - sl);
    }
    int main()
    {
        cin >> n >> k;
        for (int i = 0; i < n; ++ i) cin >> a[i];
        
        cout << quick_sort(a, 0, n - 1, k) << endl;
        
        return 0;
    }
    

    代码实现-库函数

    在algorithm头文件中存在一个nth_element的函数,同样能够找到第k个元素

    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    
    const int N = 100010;
    
    int n, k;
    int a[N];
    
    int main()
    {
        cin >> n >> k;
        for (int i = 0; i < n; ++ i) cin >> a[i];
        
        nth_element(a, a + k - 1, a + n); // 第k小的值下标为k-1
        
        cout << a[k - 1] << endl; // 第k小的值下标为k-1
        return 0;
    }
    
  • 相关阅读:
    第四周查漏补缺20165307
    第四周作业 20165307
    第三周作业 20165307
    20165307 第一次测试总结
    20165307 预备作业3 Linux安装及学习
    20165307 学习基础和C语言基础调查
    20165307 我期望的师生关系
    第十周课下补做
    20165336 2016-2017-2 《Java程序设计》第9周学习总结
    20165336 实验三 敏捷开发与XP实践
  • 原文地址:https://www.cnblogs.com/G-H-Y/p/14169742.html
Copyright © 2020-2023  润新知