快速选择算法:优化大数据中的 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 << ' ';
}
代码工作流程分析
  1. 分区过程

    • 选择中间元素作为基准(pivot)
    • 使用双指针法将数组分为两部分:左边部分大于等于基准,右边部分小于基准
    • 通过交换元素实现分区
  2. 递归策略

    • 计算左半部分的元素数量
    • 如果左半部分元素数量大于 K,则在前半部分继续查找
    • 否则在后半部分查找剩余的 K-(左半部分数量) 个元素
  3. 主函数测试

    • 生成 1000 个随机数作为测试数据
    • 分别使用快速选择和完整排序两种方法
    • 比较两种方法得到的前 10 大元素
快速选择的性能优势

快速选择算法之所以高效,是因为它每次只处理目标元素所在的那一部分子数组。在平均情况下,其时间复杂度为 O (n),而空间复杂度为 O (1)(不考虑递归栈空间)。

相比之下,完整排序算法(如快速排序、归并排序)的时间复杂度为 O (n log n),这意味着在处理大规模数据时,快速选择算法的性能优势会更加明显。

应用场景

快速选择算法在实际应用中非常广泛,特别是在需要从大量数据中找出 Top-K 元素的场景:

  • 搜索引擎中的热门搜索词统计
  • 推荐系统中的 Top-N 推荐项
  • 游戏中的排行榜系统
  • 数据挖掘中的异常检测

通过快速选择算法,我们可以在不排序整个数据集的情况下,高效地找到所需的 Top-K 元素,大大提高了处理大规模数据的效率。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/80113.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

AQS 基本思想与源码分析

充分了解 AbstractQueuedSynchronizer 对于深入理解并发编程是有益处的&#xff0c;它是用来构建锁或者其他同步组件的基础框架&#xff0c;我们常用的同步工具类如 CountDownLatch、Semaphore、ThreadPoolExecutor、ReentrantLock 和 ReentrantReadWriteLock 内部都用到了它。…

理解位图算法:使用 C++ 实现高效数据查重

在处理海量数据时&#xff0c;我们常常需要检查某个元素是否已经存在于集合中。传统的方法如哈希表或集合容器虽然有效&#xff0c;但在数据量极大的情况下会占用大量内存。这时&#xff0c;位图算法 (Bitmap) 就成为了一种非常高效的解决方案。本文将通过分析一段使用位图算法…

数学复习笔记 12

前言 现在做一下例题和练习题。矩阵的秩和线性相关。另外还要复盘前面高数的部分的内容。奥&#xff0c;之前矩阵的例题和练习题&#xff0c;也没有做完&#xff0c;行列式的例题和练习题也没有做完。累加起来了。以后还是得学一个知识点就做一个部分的内容&#xff0c;日拱一…

1-10 目录树

在ZIP归档文件中&#xff0c;保留着所有压缩文件和目录的相对路径和名称。当使用WinZIP等GUI软件打开ZIP归档文件时&#xff0c;可以从这些信息中重建目录的树状结构。请编写程序实现目录的树状结构的重建工作。 输入格式: 输入首先给出正整数N&#xff08;≤104&#xff09;…

Python爬虫实战:研究 RPC 远程调用机制,实现逆向解密

1. 引言 在网络爬虫技术的实际应用中,目标网站通常采用各种加密手段保护其数据传输和业务逻辑。这些加密机制给爬虫开发带来了巨大挑战,传统的爬虫技术往往难以应对复杂的加密算法。逆向解密作为一种应对策略,旨在通过分析和破解目标网站的加密机制,获取原始数据。 然而,…

debugfs:Linux 内核调试的利器

目录 一、什么是 debugfs&#xff1f;二、debugfs 的配置和启用方式2.1 内核配置选项2.2 挂载 debugfs2.3 Android 系统中的 debugfs 三、debugfs 的典型应用场景3.1 调试驱动开发3.2 内核子系统调试3.3 性能分析 四、常见 debugfs 子目录与功能示例4.1 /sys/kernel/debug/trac…

lua 作为嵌入式设备的配置语言

从lua的脚本中获取数据 lua中栈的索引 3 | -1 2 | -2 1 | -3 可以在lua的解释器中加入自己自定的一些功能,其实没啥必要,就是为了可以练习下lua

棋牌室台球室快速接入美团团购接口

北极星平台从2024年12月份开始慢慢关闭&#xff0c;现在很多开发者反馈北极星token已经不能刷新了&#xff0c;全部迁移到美团团购综合平台。 申请这个平台要求很高 1、保证金费用要15万起步 2、平台必须是二级等保和安全产品 &#xff0c;一个二级等保费用10万起步 所以很多…

开源轻量级地图解决方案leaflet

Leaflet 地图&#xff1a;开源轻量级地图解决方案 Leaflet 是一个开源的 JavaScript 库&#xff0c;用于在网页中嵌入交互式地图。它以轻量级、灵活性和易用性著称&#xff0c;适用于需要快速集成地图功能的项目。以下是关于 Leaflet 的详细介绍和使用指南。 1. Leaflet 的核心…

一个批量文件Dos2Unix程序(Microsoft Store,开源)1.1.0 编码检测和预览

之前的版本是个意思意思&#xff0c;验证商店发布的&#xff08;其实是我以前自己用的工具&#xff09;&#xff0c;这次把格式检查和转换都做上了&#xff0c;功能应该差不多了&#xff0c;还有一些需要小改进的地方。 因为还没什么用户嘛&#xff0c;还是保持全功能免费试用。…

特征提取:如何从不同模态中获取有效信息?

在多模态学习中&#xff0c;不同模态&#xff08;文本、图像、语音、视频、传感器数据等&#xff09;所携带的信息丰富且互补。但不同模态的数据结构、表示空间、时空分布截然不同&#xff0c;因此&#xff0c;如何对各模态进行高效、有效的特征提取&#xff0c;是整个多模态学…

Go语言爬虫系列教程 实战项目JS逆向实现CSDN文章导出教程

爬虫实战&#xff1a;JS逆向实现CSDN文章导出教程 在这篇教程中&#xff0c;我将带领大家实现一个实用的爬虫项目&#xff1a;导出你在CSDN上发布的所有文章。通过分析CSDN的API请求签名机制&#xff0c;我们将绕过平台限制&#xff0c;获取自己的所有文章内容&#xff0c;并以…

交叉熵损失函数,KL散度, Focal loss

交叉熵损失函数&#xff08;Cross-Entropy Loss&#xff09; 交叉熵损失函数&#xff0c;涉及两个概念&#xff0c;一个是损失函数&#xff0c;一个是交叉熵。 首先&#xff0c;对于损失函数。在机器学习中&#xff0c;损失函数就是用来衡量我们模型的预测结果与真实结果之间…

149.WEB渗透测试-MySQL基础(四)

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 内容参考于&#xff1a; 易锦网校会员专享课 上一个内容&#xff1a;148.WEB渗透测试-MySQL基础&#xff08;三&#xff09; 非关系型数据库&#xff1a; &a…

c/c++中程序内存区域的划分

c/c程序内存分配的几个区域&#xff1a; 1.栈区&#xff1a;在执行函数时&#xff0c;函数内局部变量的存储单元都可以在栈上创建&#xff0c;函数执行结束时这些存储单元自动被释放&#xff0c;栈内存分配运算内置于处理器的指令集中&#xff0c;效率很高但是分配的内存容量有…

构建稳定的金字塔模式生态:从自然法则到系统工程

在自然界中&#xff0c;金字塔结构广泛存在于生态系统之中&#xff0c;表现为营养级能量金字塔、生物量金字塔和数量金字塔等形式。这种结构不仅形象地描述了生态能量流转的规律&#xff0c;也体现出生态系统中“稳定性”与“层级性”的天然法则。在现代软件架构、企业组织、平…

Vue 3.0双向数据绑定实现原理

Vue3 的数据双向绑定是通过响应式系统来实现的。相比于 Vue2&#xff0c;Vue3 在响应式系统上做了很多改进&#xff0c;主要使用了 Proxy 对象来替代原来的 Object.defineProperty。本文将介绍 Vue3 数据双向绑定的主要特点和实现方式。 1. 响应式系统 1.1. Proxy对象 Vue3 …

TIP-2021《SRGAT: Single Image Super-Resolution With Graph Attention Network》

推荐深蓝学院的《深度神经网络加速&#xff1a;cuDNN 与 TensorRT》&#xff0c;课程面向就业&#xff0c;细致讲解CUDA运算的理论支撑与实践&#xff0c;学完可以系统化掌握CUDA基础编程知识以及TensorRT实战&#xff0c;并且能够利用GPU开发高性能、高并发的软件系统&#xf…

大语言模型与多模态模型比较

一、核心差异&#xff1a;输入数据类型与模态融合 输入数据类型 LLM&#xff1a;仅处理文本数据&#xff0c;例如文本分类、机器翻译、问答等任务&#xff0c;通过大规模语料库学习语言规律。 LMM&#xff1a;支持文本、图像、音频、视频等多种模态输入&#xff0c;例如根据图…

Apache HttpClient 5 用法-Java调用http服务

Apache HttpClient 5 核心用法详解 Apache HttpClient 5 是 Apache 基金会推出的新一代 HTTP 客户端库&#xff0c;相比 4.x 版本在性能、模块化和易用性上有显著提升。以下是其核心用法及最佳实践&#xff1a; 一、添加依赖 Maven 项目&#xff1a; <dependency><…