提高数据处理效率的有力工具:TopK算法解析

news2024/12/23 11:43:27

文章目录

  • TopK是什么
  • TopK算法的实现
  • 总结

在现实生活中,TopK算法是非常常见的一种应用,你可能已经在电商平台上使用它来搜索最畅销的商品或者在音乐应用中使用它来发现最受欢迎的歌曲。那么,让我们深入了解TopK算法的原理和实现吧!

TopK是什么

  • TopK算法是一种常见的统计算法,即求数据结合中前K个最大的元素或者最小的元素,一般情况下数据量都比较大。我们经常需要找出最大的十个销售额最高的商品、最受欢迎的音乐等。这时候TopK算法就非常实用,它可以帮助我们快速地找出所需数据,而不用遍历整个数组。TopK算法是一种非常高效的算法,如使用堆排序思想实现 - TopK时间复杂度为O(nlogk),n是数据的个数,k是需要查询的数据个数。

TopK算法的实现

对于Top-K问题,能想到的最简单直接的方式就是排序,但是:如果数据量非常大,排序就不太可取了(可能 数据都不能一下子全部加载到内存中),排序的效率就会变得非常低,甚至无法完成。为了解决这个问题,可以使用一些专门的技术。下面介绍一种处理大数据量Top-K问题的常见方法.

  • 基于比较的排序方法可以用来解决TopK问题,其中最著名的算法是堆排序。堆排序使用堆来维护前K个元素,堆的大小为K。基本思路如下:
  1. 用数据集合中前K个元素来建堆
  • 前k个最大的元素,则建小堆
  • 前k个最小的元素,则建大堆
  1. 用剩余的N-K个元素依次与堆顶元素来比较,(如取前k个最大)如果比堆顶的数据大,就替换他进堆. (覆盖堆顶值,向下调整)

  2. 将剩余N-K个元素依次与堆顶元素比完之后,堆中剩余的K个元素就是所求的前K个最小或者最大的元素。

  • 总的来说就是 开辟一段较小的内存空间,先将数据前K个值放入其中,然后用后续的数据逐个与堆顶数据进行比较,如果大于堆顶数据,则将其插入堆中并调整堆,这样最终堆中保留的就是前K个最大的数。

图析

  1. 用数据中前K个元素来建堆,假设k是5,把数据前5个建成堆,这个小堆用于存储当前最大的k个元素。
    在这里插入图片描述
  2. 用剩余的N-K个元素依次与堆顶元素来比较,因为堆顶元素是该堆最小值,如比堆顶元素大,就替换他进堆. (覆盖堆顶值,向下调整).
    在这里插入图片描述
    ![在这里插入图片描述](https://img-blog.csdnimg.cn/06d9d3be2d444fcc98a13e3bc7b1e29a.png
    ![在这里插入图片描述](https://img-blog.csdnimg.cn/597fc73e8f464125a547c16bd8884092.png
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

![在这里插入图片描述](https://img-blog.csdnimg.cn/625ac8230be245dc9cdd19928c58453f.png-

  • 依次与堆顶元素比完之后,堆中剩余的K个元素就是所求的前K个最大的元素。

代码实现,详细步骤已写注释

void AdjustDown(int* a, int parent, int sz)
{
    int child = parent * 2 + 1;  // 找到父节点的左孩子
    while (child < sz)  // 当左孩子在sz范围内时
    {
        if (child + 1 < sz && a[child] > a[child + 1])  // 如果左孩子比右孩子大
        {
            child++;  // 则将child指向右孩子
        }
        if (a[parent] > a[child])  // 如果父节点比最小的孩子大
        {
            int tmp = a[parent];
            a[parent] = a[child];
            a[child] = tmp;  // 则交换父节点和孩子节点的值
        }
        else  // 如果父节点比最小的孩子小则堆已经建立完成,退出循环
        {
            break;
        }
        parent = child;  // 否则,继续向下调整
        child = parent * 2 + 1;
    }
}

void PrintTopK(int* a, int n, int k)
{
    // 1. 建堆--用a中前k个元素建堆
    for (int i = (k - 1 - 1) / 2; i >= 0; i--)  // 从数组总长度的一半-1开始,向下调整每一个非叶节点
    {
        AdjustDown(a, i, k);  // 将当前节点向下调整
    }

    // 2. 将剩余n-k个元素依次与堆顶元素比较,如果大于堆顶,则替换堆顶,并向下调整
    for (int i = k; i < n; i++)
    {
        if (a[i] > a[0])  // 如果第i个元素比堆顶元素大
        {
            a[0] = a[i];  // 则将堆顶元素替换为第i个元素
            AdjustDown(a, 0, k);  // 向下调整堆顶元素
        }
    }

    // 打印前k个元素
    for (int i = 0; i < k; i++)
    {
        printf("%d ", a[i]);
    }
}

void TestTopk()
{
    int arr[] = { 6,4,10,2,8,11,3,9,1,7,12,0 };
    int sz = sizeof(arr) / sizeof(*arr);
    PrintTopK(arr, sz, 5);
}

输出结果: 8 9 10 11 12

我们换一个大一点的数据来测试一下.

void AdjustDown(int* a, int parent, int sz)
{
    int child = parent * 2 + 1;  // 找到父节点的左孩子
    while (child < sz)  // 当左孩子在sz范围内时
    {
        if (child + 1 < sz && a[child] > a[child + 1])  // 如果左孩子比右孩子大
        {
            child++;  // 则将child指向右孩子
        }
        if (a[parent] > a[child])  // 如果父节点比最小的孩子大
        {
            int tmp = a[parent];
            a[parent] = a[child];
            a[child] = tmp;  // 则交换父节点和孩子节点的值
        }
        else  // 如果父节点比最小的孩子小则堆已经建立完成,退出循环
        {
            break;
        }
        parent = child;  // 否则,继续向下调整
        child = parent * 2 + 1;
    }
}

// 打印前k个最大的元素
void PrintTopK(int* a, int n, int k)
{
    // 1. 建堆--用a中前k个元素建堆
    for (int i = (k - 1 - 1) / 2; i >= 0; i--)  // 从数组总长度的一半-1开始,向下调整每一个非叶节点
    {
        AdjustDown(a, i, k);  // 将当前节点向下调整
    }

    // 2. 将剩余n-k个元素依次与堆顶元素比较,如果大于堆顶,则替换堆顶,并向下调整
    for (int i = k; i < n; i++)
    {
        if (a[i] > a[0])  // 如果第i个元素比堆顶元素大
        {
            a[0] = a[i];  // 则将堆顶元素替换为第i个元素
            AdjustDown(a, 0, k);  // 向下调整堆顶元素
        }
    }

    // 3. 打印前k个元素
    for (int i = 0; i < k; i++)
    {
        printf("%d ", a[i]);
    }
}

// 测试函数
void TestTopk()
{
    int n = 10000;
    int* a = (int*)malloc(sizeof(int) * n);
    srand(time(0));

    // 生成数组
    for (size_t i = 0; i < n; ++i)
    {
        a[i] = rand() % 1000000;
    }

    // 修改一些元素,这些元素就是最大的.
    a[5] = 1000000 + 1;
    a[1231] = 1000000 + 2;
    a[531] = 1000000 + 3;
    a[5121] = 1000000 + 4;
    a[115] = 1000000 + 5;
    a[2335] = 1000000 + 6;
    a[9999] = 1000000 + 7;
    a[76] = 1000000 + 8;
    a[423] = 1000000 + 9;
    a[3144] = 1000000 + 10;

    // 打印前10个最大的元素
    PrintTopK(a, n, 10);
}

输出结果: 1000001 1000002 1000003 1000004 1000006 1000010 1000007 1000008 1000005 1000009


总结

堆排序是最常用的实作TopK算法的方案之一,时间复杂度为O(nlogk),n是元素总个数,k为需要找到的元素个数。TopK算法可应用于海量数据处理,如专业前10名、世界500强、富豪榜、热点事件分析等领域。总之,TopK算法通常应用于需要在大规模数据中查找最大或最小的K个元素的场景,而堆排序是实现这类算法主要的手段之一,其时间复杂度为O(nlogk)。

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

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

相关文章

一维Logistic系统分岔图matlab实现

Logistic系统被广泛应用在各个领域中&#xff0c;如生态学、物理学和社会科学等&#xff0c;也被用于密码学和数据加密中。在工业和商业中&#xff0c;混沌Logistic系统也被用于数据编码和保密通信。Logistic系统是一种非常简单的二次多项式形式的映射。 混沌Logistic系统指的…

Centos7更换OpenSSL版本

OpenSSL 1.1.0 用户应升级至 1.1.0aOpenSSL 1.0.2 用户应升级至 1.0.2iOpenSSL 1.0.1 用户应升级至 1.0.1u 查看openssl版本 openssl version -v选择升级版本 我的版本是OpenSSL 1.0.2系列&#xff0c;所以要升级1.0.2i https://www.openssl.org/source/old/1.0.2/openssl-…

MATLAB 滤波器频率特性分析

【设计目标】对典型滤波器进行时频域分析和处理的基本方法 【设计工具】MATLAB 【设计要求】 1)设计典型的滤波电路:低通、高通、带通、带阻2)理论分析各滤波电路的系统函数 3)利用Matlab分析各滤波电路的系统函数的频率特性(幅频、相频)、零极点分布 4)分析不同频率正…

(iView)表格过长省略显示且提示

(iView)表格过长省略显示且提示 效果&#xff1a; 写法&#xff1a; data(){return:{ columns: [{type: "selection",align: "center",width: 60,},{title: "名称",key: "chinese",align: "center",ellipsis: true, //1.…

STM32模拟I2C协议获取HMC5883L电子罗盘磁角度数据 (HAL)

STM32模拟I2C协议获取HMC5883L电子罗盘磁角度数据(HAL) HMC5883L 传感器采用霍尼韦尔各向异性磁阻(AMR)技术&#xff0c;应用于罗盘和三轴磁场角度检测领域&#xff0c;常用于水平物体转动的角度识别。HMC5883L 采用I2C总线接口&#xff0c;2.16~3.6V供电范围&#xff0c;带有…

利用docker compose 搭建 elasticsearch 和kibana

本文已参与「新人创作礼」活动&#xff0c;一起开启掘金创作之路。 本文介绍了从docker compose 搭建 elasticsearch 并安装IK 分词插件&#xff0c;然后再用kibana测试的详细步骤。 利用docker compose 搭建 elasticsearch 和kibana 1. 下载软件 1.1 下载镜像 docker pul…

实验技术—测序数据不好,可能是建库出了问题?(上)

回顾 在建库之前&#xff0c;我们需要对先前提取的核酸进行质检。只有质检合格的样本才能继续建库、测序、分析。&#xff08;质检的内容在上一章节也有描述&#xff09;这里再回顾下质检的内容主要分以下几部分&#xff1a; 1. 凝胶电泳实验: DNA是否降解 &#xff0c;是否有…

【Python 异步编程】零基础也能轻松掌握的学习路线与参考资料

Python 异步编程学习路线&#xff1a; 1.理解同步和异步编程模型的区别&#xff0c;了解使用异步编程的优缺点。 同步编程是指一个任务执行完毕后再执行下一个任务&#xff0c;而异步编程则是在任务执行的同时还可以继续执行其他任务。 异步编程优点&#xff1a; (1)性能优…

DC电源模块在工业自动化的应用

BOSHIDA DC电源模块在工业自动化的应用 随着自动化技术的不断发展&#xff0c;DC电源模块已成为工业控制系统中不可或缺的一个组成部分。在许多自动化系统中&#xff0c;如机器人、控制器、PLC等&#xff0c;都需要使用到直流电源模块来提供稳定可靠的电源&#xff0c;以确保系…

卷起来了,国产显卡再添新成员,主打性价比

前段时间 NVIDIA 带来了一贯甜品段位的 60 级显卡。 其拉胯的性能表现与定价策略&#xff0c;属实让咱觉得是小刀划屁股&#xff0c;开了眼。 放在以往 60 级哪次不是大幅提升&#xff0c;甚至做到越级打 80 级。 反观这代 RTX 4060 Ti 规格倒吸牙膏、性能个位数提升&#xf…

ESP-BOX在VSCODE上编译烧录

1.准备 安装好ESP-IDF和VSCODE上的扩展插件 参考安装步骤1 参考按照步骤2 2.编译和烧录 &#xff08;1&#xff09;显示所有例程 &#xff08;2&#xff09;在get-started处选择hello_world&#xff0c;然后创建项目目录 &#xff08;3&#xff09;选择芯片类型&#xff0c…

ai怎么写作?ai写作的三个步骤分享给你

随着人工智能技术的不断发展&#xff0c;越来越多的ai写作软件被应用于各种文本创作领域。这些软件可以帮助我们自动创作文章、广告、新闻等各种文本内容。但是对于初次接触这些软件的小伙伴来说&#xff0c;可能会感到有些迷惑&#xff0c;不知道ai写作软件如何使用。那么&…

网站建设需要要考虑到哪些细节

在互联网时代&#xff0c;网站是一个企业的门面&#xff0c;也是一个企业的宣传窗口&#xff0c;拥有一个好的网站可以让自己的产品和服务有更好的展示平台。现如今&#xff0c;做网站建设公司有很多&#xff0c;但是并不是所有的都是专业做网站建设的公司&#xff0c;那么如何…

C++——智能指针

目录 智能指针作用 代码 auto_ptr 特点 模拟实现 unique_ptr 模拟实现 shared_ptr 模拟实现 shared_ptr的线程安全 解决方式&#xff1a;加锁 代码 总结 循环引用 weak_ptr就可以解决这个问题 代码 模拟实现 定制删除器 智能指针作用 更好的解决了多个异常捕获不…

「消息中间件」Apache Kafka中的事务

在之前的一篇博客文章中&#xff0c;我们介绍了Apache Kafka的一次语义。这篇文章介绍了各种消息传递语义&#xff0c;介绍了幂等生成器、事务和Kafka流的一次处理语义。现在&#xff0c;我们将继续上一节的内容&#xff0c;深入探讨Apache Kafka中的事务。该文档的目标是让读者…

Arcgis进阶篇(7)——如何使用postgis实现要素服务,替代sde库

因为企业级地理信息数据库&#xff08;sde库&#xff09;需要官方许可&#xff08;这里不讨论破解&#xff0c;对于商业项目&#xff0c;没啥意义&#xff09;&#xff0c;所以自然的想到使用postgis平替sde库&#xff0c;虽然没有sde库那么强大和方便&#xff0c;但是能实现很…

socket套接字及TCP的实现框架

一、socket套接字 1.体系结构的两种形式 &#xff08;1&#xff09;网络的体系结构是计算机网络的各层及其协议的集合&#xff0c;就是这个计算机网络及其构件所应完成的功能的精确定义&#xff08;不涉及实现&#xff09;。 &#xff08;2&#xff09;实现是遵循这种体系结…

语言模型主流

词向量模型 bert4keras 字级 bert4keras 文档中心 bert4keras/examples at master bojone/bert4keras GitHub mirrors / bojone / bert4keras GitCode GitHub - bojone/bert4keras: keras implement of transformers for humans bert4keras、transformers 加载预训练bert…

[4]PCB设计实验|LPWAN物联网系统解决方案 |LoRa模块/LoRa网关/云平台/LoRa应用案例|9:30~10:00

目录 1.LPWAN物联网系统解决方案 LoRa模块/LoRa网关/云平台/LoRa应用案例 2.LoRaWAN网络部署情况 LoRaWAN网络架构 3.基于LPWAN技术的无线通信端到端解决方案 LoRa低功耗广域网智能终端 CY-LRW-102开关控制器 CY-LRB-101开关检测器 4.Lo…

软件生命周期( 包括各开发模型的优缺点)知识点全面

软件生命周期 指软件产品从计划到软件交付使用&#xff0c;直到最终退出为止的过程。包括计划阶段、分析阶段、实现阶段、测试阶段和运行维护阶段。 软件开发模型 瀑布模型、螺旋模型、喷泉模型、原型化模型、演化模型 瀑布模型&#xff1a;严格遵循软件生命周期各阶段的固定顺…