快速排序模板

快排核心问题

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

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

  1. 在分子区间端点时,为什么是[l,j],[j+1,r][l,i1],[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+n2+n4+ ... = n(1+12+14+ ...)<=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;
}
posted @   0x7F  阅读(138)  评论(0编辑  收藏  举报
编辑推荐:
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
阅读排行:
· 终于写完轮子一部分:tcp代理 了,记录一下
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
点击右上角即可分享
微信分享提示