【数据结构】堆的应用-----TopK问题

这篇具有很好参考价值的文章主要介绍了【数据结构】堆的应用-----TopK问题。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

一、前言

二、Top-k问题 

 💦解法一:暴力排序

💦解法二:建立N个数的堆

💦解法三:建立K个数的堆(最优解)

三、完整代码和视图 

四、共勉


一、前言

在之前的文章中,已经详细的讲解了二叉树、堆、堆排序。那么关于堆还有一个比较有意思的题,就是TopK问题。

如果对堆和二叉树还不够了解的可以看看我之前的文章哦!!!

详解二叉树和堆

二、Top-k问题 

Top-k问题:在 N 个数中,找出前 K 个(最大/最小)的元素,一般情况下数据量 N 都远大于 k。

Top-k问题在生活中是非常的常见,比如游戏中某个大区某个英雄熟练度最高的前10个玩家的排名,我们就要根据每个玩家对该英雄的熟练度进行排序,可能有200万个玩家,但我只想选出前10个,要对所有人去排个序吗?显然没这个必要。

再比如:专业前10名、世界500强、富豪榜、游戏中前100的活跃玩家等。

 💦解法一:暴力排序

对于Top-K问题,首先想到的最简单直接的方式就是排序。

我们用堆排序,其时间复杂度为:O(N*log2N)。

但是:如果数据量非常大,排序就不太可取了(可能数据都不能一下子全部加载到内存中)。


💦解法二:建立N个数的堆

建一个 N 个数的堆(C++中可用优先级队列priority_queue),不断的选数,选出前 k 个。

时间复杂度:建N个数的堆为O(N),获取堆顶元素 (也即是最值) 并删除掉堆顶元素为O(log2N),上述操作重复 k 次,所以时间复杂度为O(N+k*log2N)。

【思考】

能否再优化一下呢?假设 N 是 10 亿数,内存中放不下,是放在文件中的。前面两个方法都不能用了。


💦解法三:建立K个数的堆(最优解)

✨基本思想:

用数据集合中前K个元素来建堆。

找前 k 个最大的元素,则建小堆

找前 k 个最小的元素,则建大堆

用剩余的 N-K 个元素依次与堆顶元素来比较,不满足则删除堆顶元素,再插入。

找前 k 个最大的元素,大于堆顶元素,则删除堆顶元素,再插入

找前 k 个最小的元素,小于堆顶元素,则删除堆顶元素,再插入

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


✨时间复杂度:

▶ 建 k 个元素的堆为O(K);
▶ 遍历剩余的 N-K 个元素的时间代价为O(N-K),假设运气很差,每次遍历都入堆调整;
▶ 入堆调整:删除堆顶元素和插入元素都为O(log2K);
▶ 所以时间复杂度为O(k + (N-K)log2K)。当 N 远大于 K 时,为O(N*log2K),这种解法更优。

 

✨假如要找出最大的前 10 个数

▶ 建立 10 个元素的小堆,数据集合中前 10 个元素依次放入小堆,此时的堆顶元素是堆中最小的元素,也是堆里面第 10 个最小的元素,
▶  然后把数据集合中剩下的元素与堆顶比较,若大于堆顶则去掉堆顶,再将其插入,
▶  这样一来,堆里面存放的就是数据集合中的前 10 个最大元素,
此时小堆的堆顶元素也就是堆中的第 10 个最大的元素

 

✨思考:为什么找出最大的前10个数,不能建大堆呢?

如果你建的10个元素的大堆,堆顶元素恰好是数据集合中最大的那个,那第2大的数、第3大的数不就能找不到了。

三、完整代码和视图 

以从1w个数里找出最大的前10个数为例:

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>

typedef int HPDatatype;
void Swap(HPDatatype* x, HPDatatype* y)
{
	HPDatatype temp = 0;
	temp = *x;
	*x = *y;
	*y = temp;
}

void AdjustDown(HPDatatype* a,int n,int parent)
{
	// 左孩子
	int child = parent * 2 + 1;
	// 防止越界
	while (child < n)
	{
		//小堆
		if (child + 1 < n && a[child] > a[child + 1])
		{
			child++;
		}

		// 开始向下调整
		if (a[child] < a[parent])
		{
			Swap(&a[child], &a[parent]);
			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
			break;
		}
	}
}

void TopK(HPDatatype* a, int n, int k)
{
	HPDatatype* kminHeap = (HPDatatype*)malloc(sizeof(HPDatatype) * k);
	assert(kminHeap);
	// 1. 建堆----用a中前k个元素建堆
	for (int i = 0; i < k; i++)
	{
		kminHeap[i] = a[i];
	}
	// 建小堆
	for (int j = ((n - 1) - 1) / 2; j >= 0; j--)
	{
		// 从倒数第一个非叶子节点开始
		AdjustDown(kminHeap, k, j);
	}
	// 2. 将剩余n-k个元素依次与堆顶的元素交换,比堆顶大,交换
	for (int i = k; i < n; i++)
	{
		if (a[i] > kminHeap[0])
		{
			kminHeap[0] = a[i];//如果比堆顶大,就替换
			AdjustDown(kminHeap, k, 0);//向下调整确保为堆
		}
	}
	for (int j = 0; j < k; j++)
	{
		printf("%d ", kminHeap[j]);
	}
	printf("\n");
	free(kminHeap);
}


int main()
{
	int n = 10000;
	int* a = (int*)malloc(sizeof(int) * n);
	srand(time(0));
	for (int i = 0; i < n; ++i)
	{
		a[i] = rand() % 1000000; //产生一个随机数,数值均小于100万
	}
	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;
	TopK(a, n, 10);
	return 0;
}

【数据结构】堆的应用-----TopK问题,数据结构,数据结构,算法,c语言,开发语言,c++

四、共勉

 以下就是我对数据结构---堆排序的理解,如果有不懂和发现问题的小伙伴,请在评论区说出来哦,同时我还会继续更新对数据结构-------链式二叉树请持续关注我哦!!!!

【数据结构】堆的应用-----TopK问题,数据结构,数据结构,算法,c语言,开发语言,c++文章来源地址https://www.toymoban.com/news/detail-727426.html

到了这里,关于【数据结构】堆的应用-----TopK问题的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 数据结构:手撕图解堆的实现和TopK的应用

    要讲到堆,先要说两个关于二叉树的概念 满二叉树:一个二叉树如果每一层的节点数都是最大值,那么这个二叉树就是满二叉树 完全二叉树:完全二叉树是效率很高的数据结构,完全二叉树是满二叉树的变形,对于深度为k的树有n个节点的二叉树,当且仅当其每一个节点都与

    2024年02月15日
    浏览(39)
  • 数据结构---手撕图解堆的实现和TopK的应用

    要讲到堆,先要说两个关于二叉树的概念 满二叉树:一个二叉树如果每一层的节点数都是最大值,那么这个二叉树就是满二叉树 完全二叉树:完全二叉树是效率很高的数据结构,完全二叉树是满二叉树的变形,对于深度为k的树有n个节点的二叉树,当且仅当其每一个节点都与

    2024年02月16日
    浏览(30)
  • 数据结构学习分享之堆的详解以及TopK问题

    💓博主CSDN主页:杭电码农-NEO💓   ⏩专栏分类:数据结构学习分享⏪   🚚代码仓库:NEO的学习日记🚚   🌹关注我🫵带你了解更多数据结构的知识   🔝🔝 本章就给大家带来久违的堆的知识,如果你还不知道数的相关知识,或者什么是完全二叉树,请跳转 树的介绍, 本章的堆结

    2024年02月05日
    浏览(71)
  • 经典TopK问题、优先级队列 与 堆的纠葛一文为你解惑——数据结构

    前言: 本篇文章以 TopK 问题为引,具体阐述了 PriorityQueue 实现的基本逻辑——堆 数据结构,以及PriorityQueue 的常用方法。如有问题欢迎看官朋友指正,如果觉得文章还不错的话,求点赞、收藏、评论 三连。 重点: 堆的基本实现逻辑 PriorityQueue 运用和源码分析 TopK 问题的解法

    2023年04月22日
    浏览(34)
  • 堆排序+TopK问题——“数据结构与算法”

    各位CSDN的uu们你们好呀,好久不见,停更了很长一段时间吧,最近小雅兰会开始慢慢更新起来的,下面,就进入小雅兰今天的分享的知识点吧,让我们一起进入堆的世界!!! 堆排序——(1) heap.h的内容: heap.c的内容: test.c的内容: 这样的堆排序其实也是可以的 但是有弊

    2024年02月13日
    浏览(32)
  • 【数据结构之二叉树简介·顺序存储·应用:堆·堆排序·TOPK问题】

    ​ 🕺作者: 迷茫的启明星 😘欢迎关注:👍点赞🙌收藏✍️留言 🎃相关文章 【数据结构从0到1之树的初识】 【数据结构】带你学会二叉树的链式存储的前中后序遍历,遍历推导及利用队列实现二叉树的层次遍历。 🏇家人们,码字不易,你的👍点赞🙌收藏❤️关注对我

    2024年02月01日
    浏览(27)
  • 【数据结构和算法】---二叉树(2)--堆的实现和应用

    如果有一个数字集合,并把它的所有元素 按完全二叉树的顺序存储方式存储在一个一维数组中 ,且在逻辑结构(即二叉树)中,如果 每个父亲节点都大于它的孩子节点那么此堆可以称为大堆 ;那么如果 每个父亲节点都小于它的孩子节点那么此堆可以称为小堆 。 堆的 性质

    2024年02月03日
    浏览(33)
  • 【数据结构】堆的应用+TOP-K问题+二叉树遍历

    欢迎来到我的: 世界 希望作者的文章对你有所帮助,有不足的地方还请指正,大家一起学习交流 ! 该篇文章写到主要是:堆排序、 TOP-K问题、二叉树链式结构的实现、二叉树的遍历等等;如果有朋友还不太了解堆以及二叉树可以翻看我的上一篇博客:堆和二叉树的概念; 最

    2024年02月07日
    浏览(43)
  • 数据结构-堆的实现及应用(堆排序和TOP-K问题)

    1.堆的知识点: 下面我们通过一张图片来更加深刻地理解堆 上面我们说过,堆的物理结构是一个数组,逻辑结构是一个完全二叉树,所以堆的实际结构类似于顺序表,只不过我们的处理方式类似于二叉树 那么我们就可以用顺序表那样的结构来表示堆了 于是我们可以写出这样的代码

    2024年02月07日
    浏览(41)
  • 数据结构进阶篇 之 【堆的应用】(堆排序,TOP-K问题)详细讲解

    所有人都关心我飞的高不高,只有我妈关心我翅膀硬不硬 1.1 建堆 1.2 利用堆删除思想来进行排序 –❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀-正文开始-❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀– 学习一个知识,我们起码要直

    2024年04月10日
    浏览(37)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包