首页 > 编程语言 >快速选择算法

快速选择算法

时间:2023-06-14 10:37:11浏览次数:37  
标签:arr 元素 中位数 选择 算法 pivot 快速 rk

问题描述

给定一个长度为$n$的数组,如何在$O(n)$的时间复杂度内找到第$k$大的数。

思路

朴素的想法是先排序,然后直接找到第$k$个元素,时间复杂度为$O(n\log n)$。

我们可以利用快速排序的思想来解决这个问题,考虑快速排序的划分过程,在快速排序的“划分”结束后,数组$A_p \cdots A_r$被分成了$A_p\cdots A_q$和$A_{q+1}\cdots A_r$,此时可以按照左边元素的个数($q-p+1$)和$k$的大小关系来判断是只在左边还是右边递归的求解。

代码

template <Typename T> // 类型T需要定义 < 运算
// arr 为查找范围数组,rk 为需要查找的排名(从 0 开始),len 为数组长度
T find_kth_element(T arr[], int rk, const int len) {
    if (len <= 1) {
        return arr[0];
    }
    // 随机选择基准
    const T pivot = arr[rand() % len];
    // i 当前操作的元素
    // j 第一个等于pivot的元素
    // k 第一个大于pivot的元素
    // 完成一趟三路快排,将序列分为:
    // 小于 pivot 的元素 | 等于 pivot 的元素 | 大于 pivot 的元素
    int i = 0, j = 0, k = len;
    while (i < k) {
        if (arr[i] < pivot) {
            swap(arr[i++], arr[j++]);
        } else if (arr[i] > pivot) {
            swap(arr[i], arr[--k]);
        } else {
            ++i;
        }
    }
    // 根据要找的排名与两条分界线的位置,去不同的区间递归查找第k大的数
    // 如果小于pivot的元素个数比k多,则第k大的元素一定是一个小于pivot的数
    if (rk < j) {
        return find_kth_element(arr, rk, j);
    } else if (rk >= k){
        // 否则,如果小于pivot和等于pivot的元素加起来也没有k多
        // 则第k大的元素一定是一个大于pivot的元素
        return find_kth_element(arr + k, rk - k, len - k);
    } else {
        // 否则,pivot就是第k大的元素
        return pivot;
    }
}

优化:中位数的中位数

中位数中的中位数(英文:Median of medians),提供了一种确定性的选择划分过程中分界值的方法,从而能够让找第$k$大的数算法在最坏情况下也能实现线性时间复杂度。

该算法的流程如下:

  • 将整个序列划分为 $\left \lfloor \dfrac{n}{5} \right \rfloor$组,每组元素数不超过$5$个;
  • 寻找每组元素的中位数(因为元素个数较少,可以直接使用插入排序等算法);
  • 找出这$\left \lfloor \dfrac{n}{5} \right \rfloor$组元素中位数中的中位数。将该元素作为前述算法中每次划分时的分界值即可。

该优化后,最坏情况下,算法也有$O(n)$的时间复杂度。

参考

OI-Wiki:快速排序

标签:arr,元素,中位数,选择,算法,pivot,快速,rk
From: https://www.cnblogs.com/zwyyy456/p/17479466.html

相关文章

  • LRU 算法与 LFU 算法
    算法介绍LRULRU全称是LeastRecentlyUsed,即最近最久未使用算法。LRU根据数据的历史访问记录来进行淘汰数据,其核心思想是“如果数据最近被访问过,那么将来被访问的几率也更高,它是页面置换算法的一种,也常用于缓存设计。LFULFU全称是LeastFrequentlyUsed,根据频率来选择要......
  • kmp 算法
    问题描述kmp算法解决的是字符串匹配问题,即:字符串P是否是字符串S的子串?如果是,它出现在s的哪些位置?这里我们称S为主串,P为模式串。思路首先是暴力匹配算法(Brute-Force算法),代码如下:voidBruteForce(strings,stringp){intlen_s=s.size(),len_p=p.size();fo......
  • sqlserver使用between and 筛选时间,两个时间段选择一样筛选当天的数据无法筛选
    一般我们使用时间筛选代码是select*from表名wheredatebetweenRQANDRQ1但是这样子是无法筛选当天数据的,想要筛选当天数据得对这个代码进行一下修改,这里是sqlserver的代码select*from表名whereCONVERT(nvarchar(10),date,120)betweenRQANDRQ1   mysql代码如......
  • 【基础算法】单链表的OJ练习(2) # 链表的中间结点 # 链表中倒数第k个结点 #
    前言对于单链表的OJ练习,<fontcolor=bluesize=4>需要深刻理解做题的思路</font>,这样我们才能够在任何场景都能够熟练的解答有关链表的问题。关于OJ练习(1):==->==传送门==<-==,其题目较为简单,思路也好理解,本章与(1)差不多,难度不大,<fontcolor=orangesize=4>核心点就在于理解解......
  • 如何快速搭建微服务架构
    微服务架构是一种分布式系统设计,它将应用程序拆分成多个独立的、互相通信的服务,每个服务都负责实现特定的功能。这种架构可以提高系统的可扩展性、容错性和开发效率,是现代软件开发中的一种主流架构。本文将介绍如何快速搭建微服务架构,帮助读者掌握这一重要技能。一、选择合适的工具......
  • 马拉车算法
    截图来自董老师https://www.bilibili.com/video/BV173411V7Ai/?spm_id_from=333.999.0.0&vd_source=23dc8e19d485a6ac47f03f6520fb15c2  P3805【模板】manacher算法#include<iostream>#include<cstring>#include<cmath>#include<algorithm>#include......
  • 【VRP问题】基于遗传算法求解多约束多无人机灾情应急救援路径规划问题附matlab代码
    ✅作者简介:热爱科研的Matlab仿真开发者,修心和技术同步精进,matlab项目合作可私信。......
  • 多种智能优化算法运行时间和不同函数测试对比附matlab代码
    ✅作者简介:热爱科研的Matlab仿真开发者,修心和技术同步精进,matlab项目合作可私信。......
  • 《数据结构与算法》之二叉树(补充树)
    一.树结构之二叉树操作二叉树的查找二叉搜索树,也称二叉排序树或二叉查找树二叉搜索树:一棵二叉树,可以为空,如果不为空,应该满足以下性质:非空左子树的所有结点小于其根结点的键值非空右子树的所有结点大于其根结点的键值左右子树都是二叉搜索树对于二叉树的查找,其实沿用的是......
  • 文心一言 VS 讯飞星火 VS chatgpt (40)-- 算法导论5.4 4题
    四、一次聚会需要邀请多少人,才能让其中3人的生日很可能相同?文心一言:为了解决这个问题,我们需要先计算出所有可能的生日组合数,然后计算出其中生日相同的组合数。已知需要邀请的人数为:23人根据组合数公式,可计算出所有可能的生日组合数:2.58520167*10^{22}根据生日相同的组合......