快速选择算法:优化大数据中的 Top-K 问题
在处理海量数据时,经常会遇到这样的需求:找出数据中最大的前 K 个数,而不必对整个数据集进行排序。这种场景下,快速选择算法(Quickselect)就成了一个非常高效的解决方案。本文将通过一个 C++ 实现的快速选择算法来详细讲解其原理和应用。
快速选择算法原理
快速选择算法是由 Tony Hoare 在 1961 年提出的,它基于快速排序(Quicksort)的思想。与快速排序不同的是,快速选择只需要处理包含目标元素的那一部分子数组,因此其平均时间复杂度为 O (n),优于排序算法的 O (n log n)。
快速选择的核心思想是利用快速排序中的分区(partition)过程:选择一个基准元素(pivot),将数组分为两部分,使得左边部分的所有元素都大于等于基准元素,右边部分的所有元素都小于基准元素。然后根据基准元素的位置与 K 的关系,决定是继续在左半部分还是右半部分查找。
代码实现与解析
下面是一个使用快速选择算法查找前 K 大元素的 C++ 实现:
#include<iostream>
#include<algorithm>
#include<vector>
#include<time.h>
using namespace std;// 快速选择函数:查找数组中前top大的元素
template<class T>
void find(vector<T>& q, int top, int l, int r) {if (l >= r) return;// 选择中间元素作为基准int mid = (l + r) / 2;T val = q[mid];// 初始化左右指针int i = l;int j = r;// 分区过程while (i < j) {// 从左向右找到第一个小于等于基准的元素while (q[i] > val && i < j) i++;// 从右向左找到第一个大于等于基准的元素while (q[j] < val && i < j) j--;// 交换这两个元素if (i < j) swap(q[i], q[j]);else break;}// 根据分区结果递归处理if (j - l + 1 > top) {// 左半部分元素数量大于top,在前半部分继续查找find(q, top, l, i);} else {// 否则在后半部分查找剩余的元素find(q, top - (j - l + 1), i + 1, r);}
}int main() {vector<double> q;vector<double> q1; // 存储快速选择结果vector<double> q3; // 存储排序结果用于对比// 生成测试数据srand(time(NULL));for (int i = 0; i < 1000; i++) {q.push_back(rand() % 10000 + i * 1.0 / 100);}q3 = q;// 使用快速选择算法查找前10大的元素find(q, 10, 0, 999);// 将结果存入q1for (int i = 0; i < 10; i++) q1.push_back(q[i]);// 对原数组进行降序排序sort(q3.rbegin(), q3.rend());// 对快速选择的结果进行降序排序sort(q1.rbegin(), q1.rend());// 输出结果cout << "快速选择结果:";for (auto i : q1) cout << i << ' ';cout << endl;cout << "完整排序结果:";for (auto i : q3) cout << i << ' ';
}
代码工作流程分析
-
分区过程:
- 选择中间元素作为基准(pivot)
- 使用双指针法将数组分为两部分:左边部分大于等于基准,右边部分小于基准
- 通过交换元素实现分区
-
递归策略:
- 计算左半部分的元素数量
- 如果左半部分元素数量大于 K,则在前半部分继续查找
- 否则在后半部分查找剩余的 K-(左半部分数量) 个元素
-
主函数测试:
- 生成 1000 个随机数作为测试数据
- 分别使用快速选择和完整排序两种方法
- 比较两种方法得到的前 10 大元素
快速选择的性能优势
快速选择算法之所以高效,是因为它每次只处理目标元素所在的那一部分子数组。在平均情况下,其时间复杂度为 O (n),而空间复杂度为 O (1)(不考虑递归栈空间)。
相比之下,完整排序算法(如快速排序、归并排序)的时间复杂度为 O (n log n),这意味着在处理大规模数据时,快速选择算法的性能优势会更加明显。
应用场景
快速选择算法在实际应用中非常广泛,特别是在需要从大量数据中找出 Top-K 元素的场景:
- 搜索引擎中的热门搜索词统计
- 推荐系统中的 Top-N 推荐项
- 游戏中的排行榜系统
- 数据挖掘中的异常检测
通过快速选择算法,我们可以在不排序整个数据集的情况下,高效地找到所需的 Top-K 元素,大大提高了处理大规模数据的效率。
相关文章:
快速选择算法:优化大数据中的 Top-K 问题
在处理海量数据时,经常会遇到这样的需求:找出数据中最大的前 K 个数,而不必对整个数据集进行排序。这种场景下,快速选择算法(Quickselect)就成了一个非常高效的解决方案。本文将通过一个 C 实现的快速选择算…...
使用Frp搭建内网穿透,外网也可以访问本地电脑。
一、准备 1、服务器:需要一台外网可以访问的服务器,不在乎配置,宽带好就行。我用的是linux服务器。(一般买一个1核1g的云服务器就行),因为配置高的服务器贵,所以这是个择中办法。 2、客户端&a…...
【RabbitMQ】消息丢失问题排查与解决
RabbitMQ 消息丢失是一个常见的问题,可能发生在消息的生产、传输、消费或 Broker 端等多个环节。消息丢失的常见原因及对应的解决方案: 一、消息丢失的常见原因 1. 生产端(Producer)原因 (1) 消息未持久化 原因:生产…...
电子电路:被动电子元件都有哪些?
在电子电路中,被动元件(Passive Components)是指不需要外部电源即可工作且不具备信号放大或能量控制能力的元件。它们主要通过消耗、存储或传递能量来调节电路的电流、电压、频率等特性。以下是常见的被动元件及其核心作用: 一、基础被动元件 1. 电阻(Resistor) 功能:限…...

使用Mathematica制作Lorenz吸引子的轨道追踪视频
Lorenz奇异吸引子是混沌理论中最早被发现和研究的吸引子之一,它由Edward Lorenz在1963年研究确定性非周期流时提出。Lorenz吸引子以其独特的"蝴蝶"形状而闻名,是混沌系统和非线性动力学的经典例子。 L NDSolveValue[{x[t] -3 (x[t] - y[t]),…...
深入解析VPN技术原理:安全网络的护航者
在当今信息化迅速发展的时代,虚拟私人网络(VPN)技术成为了我们在互联网时代保护隐私和数据安全的重要工具。VPN通过为用户与网络之间建立一条加密的安全通道,确保了通讯的私密性与完整性。本文将深入解析VPN的技术原理、工作机制以…...
JavaScript性能优化实战(10):前端框架性能优化深度解析
引言 React、Vue、Angular等框架虽然提供了强大的抽象和开发效率,但不恰当的使用方式会导致严重的性能问题,针对这些问题,本文将深入探讨前端框架性能优化的核心技术和最佳实践。 React性能优化核心技术 React通过虚拟DOM和高效的渲染机制提供了出色的性能,但当应用规模…...
(for 循环) VS (LINQ) 性能比拼 ——c#
在大多数情况下,for 循环的原始性能会优于 LINQ,尤其是在处理简单遍历、数据筛选或属性提取等场景时。这是由两者的实现机制和抽象层次决定的。以下是具体分析: 一、for 循环与 LINQ 的性能差异原因 1. 抽象层次与执行机制 for 循环&#…...
《Spring Boot 4.0新特性深度解析》
Spring Boot 4.0的发布标志着Java生态向云原生与开发效能革命的全面迈进。作为企业级应用开发的事实标准框架,此次升级在运行时性能、云原生支持、开发者体验及生态兼容性四大维度实现突破性创新。本文深度解析其核心技术特性,涵盖GraalVM原生镜像支持、…...
【大模型面试每日一题】Day 20:大模型出现“幻觉”(Hallucination)的可能原因有哪些?如何从数据或训练层面缓解?
【大模型面试每日一题】Day 20:大模型出现“幻觉”(Hallucination)的可能原因有哪些?如何从数据或训练层面缓解? 📌 题目重现 🌟🌟 面试官:大模型出现“幻觉”…...

简单图像自适应亮度对比度调整
一、背景介绍 继续在刷对比度调整相关算法,偶然间发现了这个简单的亮度/对比度自适应调整算法,做个简单笔记记录。也许后面用得到。 二、自适应亮度调整 1、基本原理 方法来自论文:Adaptive Local Tone Mapping Based on Retinex for High Dynamic Ran…...
CompletableFuture统计任务
ApiOperation(value "首页统计")GetMapping("/statistics")public UnifyResponse<List<BusinessStatisticsVO>> statistics() throws Exception {StatisticsPermissionQuery permissionQuery getPermission();ThreadPoolExecutor executor …...
neo4j框架:ubuntu系统中neo4j安装与使用教程
在使用图数据库的时候,经常需要用到neo4j这一图数据库处理框架。本文详细介绍了neo4j安装使用过程中的问题与解决方法。 一、安装neo4j 在安装好了ubuntu系统、docker仓库和java的前提下 在ubuntu系统命令行依次输入如下命令: # 安装依赖库 sudo apt-…...
ECPF 简介
ECPF(Embedded CPU Function,嵌入式CPU功能)是NVIDIA BlueField DPU特有的一种功能类型,和PF(Physical Function,物理功能)、VF(Virtual Function,虚拟功能)密…...
eSwitch manager 简介
eSwitch manager 的定义和作用 eSwitch manager 通常指的是能够配置和管理 eSwitch(嵌入式交换机)的实体或接口。在 NVIDIA/Mellanox 的网络架构中,Physical Function(PF)在 switchdev 模式下充当 eSwitch manager&am…...

深入理解二叉树:遍历、存储与算法实现
在之前的博客系列中,我们系统地探讨了多种线性表数据结构,包括顺序表、栈和队列等经典结构,并通过代码实现了它们的核心功能。从今天开始,我们将开启一个全新的数据结构篇章——树结构。与之前讨论的线性结构不同,树形…...
Python3 简易DNS服务器实现
使用Python3开发一个简单的DNS服务器,支持配置资源记录(RR),并能通过dig命令进行查询。 让自己理解DNS原理 实现方案 我们将使用socketserver和dnslib库来构建这个DNS服务器。dnslib库能帮助我们处理DNS协议的复杂细节。 1. 安装依赖 首先确保安装了d…...

【Win32 API】 lstrcmpA()
作用 比较两个字符字符串(比较区分大小写)。 lstrcmp 函数通过从第一个字符开始检查,若相等,则检查下一个,直到找到不相等或到达字符串的末尾。 函数 int lstrcmpA(LPCSTR lpString1, LPCSTR lpString2); 参数 lpStr…...

(C语言)超市管理系统 (正式版)(指针)(数据结构)(清屏操作)(文件读写)
目录 前言: 源代码: product.h product.c fileio.h fileio.c main.c 代码解析: 一、程序结构概述 二、product.c 函数详解 1. 初始化商品列表 Init_products 2. 添加商品 add_product 3. 显示商品 display_products 4. 修改商品 mo…...

NAT转换和ICMP
NAT nat原理示意 nat实现 ICMP ICMP支持主机或路由器: 差错或异常报告网络探寻 2类icmp报文: 差错报告报文(5种) 目的不可达源抑制--拥塞控制超时&超期--TTL超时参数问题--问题报文丢弃重定向--不应该由这个路由器转发&a…...
Executors类详解
Executors类详解 Executors 是Java中用于快速创建线程池的工具类,提供了一系列工厂方法,简化了 ThreadPoolExecutor 和 ScheduledThreadPoolExecutor 的配置。以下是其核心方法、实现原理及使用注意事项: 1. 常用线程池工厂方法 (1) newFixedThreadPool 作用:创建固定大小…...

【专利信息服务平台-注册/登录安全分析报告】
前言 由于网站注册入口容易被黑客攻击,存在如下安全问题: 暴力破解密码,造成用户信息泄露短信盗刷的安全问题,影响业务及导致用户投诉带来经济损失,尤其是后付费客户,风险巨大,造成亏损无底洞…...

BUUCTF——web刷题第一页题解
共31题,admin那题没有,因为环境问题,我做的非常卡 目录 极客大挑战 2019]Havefun [HCTF 2018]WarmU [ACTF2020 新生赛]Include [ACTF2020 新生赛]Exec [GXYCTF2019]Ping Ping Ping [SUCTF 2019]EasySQL [极客大挑战 2019]LoveSQL [极…...

哪个品牌的智能对讲机好用?推荐1款,能扛事更智能
在专业通信领域,智能对讲机早已突破传统设备的局限,成为集通信、调度、数据传输于一体的智能化终端。面对复杂多变的作业环境,用户对设备的稳定性、通信效率和智能化水平提出了更高要求。但是,市面上产品同质化严重,部…...

【Win32 API】 lstrcpyA()
作用 将字符串复制到指定的字符串缓冲区。 函数 LPSTR lstrcpyA(LPSTR lpString1, LPCSTR lpString2); 参数 lpString1 类型:LPTSTR 一个缓冲区,用于接收由 lpString2 参数指向的字符串的内容。 缓冲区必须足够大才能包含字符串,包括终止…...

Vue3——Watch侦听器
目录 手动指定监听对象 侦听ref对象 侦听ref对象中的某个属性 reactive写法 watchEffect 自动侦听 多源侦听 一次性侦听器 watch 是⼀个⽤于观察和响应Vue响应式系统中数据变化的⽅法。它允许你指定⼀个数据源(可以是 响应式引⽤、计算属性、组件的属性等…...

Go的单测gomock及覆盖率命令
安装gomock: go get github.com/golang/mock/gomockgo get github.com/golang/mock/mockgen 使用 mockgen 生成 mock 代码: 参考 mockgen -sourceservice/user.go -destinationservice/mocks/mock_user_service.go -packagemocks go test -coverprofilecoverage.out…...

Leetcode209做题笔记
力扣209 题目分析:想象一个窗口遍历着这个数组,不断扩大右边界,让r。往窗口中添加数字: 此时我们找到了这个窗口,它的和满足了大于等于target的条件,题目让我求最短的,那么我们就尝试来缩短它&…...

Suna: 开源多面手 AI 代理
GitHub:GitHub - kortix-ai/suna: Suna - Open Source Generalist AI Agent 更多AI开源软件:发现分享好用的AI工具、AI开源软件、AI模型、AI变现 - 小众AI Suna 是一个完全开源的 AI 助手,可帮助您轻松完成实际任务。通过自然对话,…...

25-05-16计算机网络学习笔记Day1
深入剖析计算机网络:今日学习笔记总结 本系列博客源自作者在大二期末复习计算机网络时所记录笔记,看的视频资料是B站湖科大教书匠的计算机网络微课堂,每篇博客结尾附书写笔记(字丑见谅哈哈) 视频链接地址 一、计算机网络基础概念 …...