【数据结构】堆的应用——Top-K

目录

前言:

一、Top-K问题描述:

二、不同解决思路实现:

①.排序法:

②.直接建堆法:

③.K堆法

总结:

前言:

上篇文章我们学习了二叉树的顺序存储结构,并且对于实际使用中所常用的顺序存储结构------堆的各个接口进行实现。这篇文章我们将对堆的实际应用进行更加深入的研究。

一、Top-K问题描述:

Top-K问题,就是求数据结合前K个最大的元素或者最小的元素,一般情况下数据量较大。比如:美团上的附近美食排行榜、年纪成绩排行榜等等。

而对于Top-K问题,我们能想到的有三种不同的思路去解决。 首先最简单直接的方式就是排序。但是如果需要处理的数据量非常大,排序就不太可取了。而另外两种方法就是使用堆:

  1. 用数据集合中前K个元素来建堆, 若要取前K个最大的元素,则建小堆; 若要取前K个最小的的元素,则建大堆
  2. 用剩余的N-K个元素依次与堆顶元素来比较,不满足则替换堆顶元素, 最终堆中剩余的K个元素就是所求的前K个最小或者最大的元素。

二、不同解决思路实现:

①.排序法:

排序法的思路很好理解,就是**将所有的数据进行排序,再根据需求取值即可。**过程中使用的排序方法就是向下调整,时间复杂度是O(nlogn):

cpp 复制代码
//排序法:
Swap(int* a, int* b)
{
	int tmp = *a;
	*a = *b;
	*b = tmp;
}
void HeapSort(int* a, int n)
{
	for (int i = 1; i < n; i++)
	{
		Adujustup(a, i);
	}

	while ((n-1) > 0)
	{
		
		Swap(&a[0], &a[n - 1]);
		n--;
		Adujustdown(a, n-1, 0);
	}
}

这种方法就**相当于遍历所有的数据进行比较排序,因此会将会造成大量的内存消耗和使用,**存在着较大的弊端。

②.直接建堆法:

直接建堆法的作用原理为:建立一个大堆(时间复杂度O(logn)),然后取出堆顶元素并将其删除,然后调整堆,重复这个步骤K次。

cpp 复制代码
void HeapSort(int* a, int n)
{
	for (int i = 1; i < n; i++)
	{
		Adujustup(a, i);
	}
    for(int i=0;i<k;i++)
    {
        printf("%d",HeapTop(a));
        HeapPop(a);
    }

虽然这种算法有了一定程度的改进,但是仍然没有改变再内存中进行操作的本质,其操作方式仍然会造成大量内存的占用和消耗。

③.K堆法

由于上述两种方法都是当n很大时,所占用的内存将会非常大,例如我们假设n为100亿,此时便有:1G=1024Mb=1024*1024Kb=1024*1024*1024Byte,需要使用内存将达到10byte。

于是我们就采用另外一种建堆方式------K堆法:建一个大小为K的小堆。

为什么时小堆呢?

因为小堆的堆顶是K的元素中最小的,而我每次只需要跟堆顶比较然后淘汰K个元素中最

小的一个,最后N-K比较完之后这K个元素就是TopK了。

cpp 复制代码
void TestTopk(HP* p, int k)
{
	int* arr = (int*)malloc(sizeof(int) * k);
	int n = p->size;
	for (int i = 1; i < n; i++)
	{
		SAdujustup(p->a, i);
	}
	for (int i = 0; i < k; i++)
	{
		arr[i] = p->a[0];
		p->a[0] = p->a[p->size - 1];
		p->size--;
		n = p->size;
		for (int i = 1; i < n; i++)
		{
			SAdujustup(p->a, i);
		}
	}
	for (int i = 1; i < k; i++)
	{
		SAdujustup(arr, i);
	}
	for (int i = 0; i < k; i++)
	{
		printf("%d ", arr[i]);
	}
}

总结:

到这里,我们今天关于Topk问题的研究就全部结束了,难度不大,最主要是结合具体情况,选择最合适的方法建堆。

相关推荐
稚辉君.MCA_P8_Java5 分钟前
Gemini永久会员 C++返回最长有效子串长度
开发语言·数据结构·c++·后端·算法
dragoooon341 小时前
[优选算法专题十.哈希表 ——NO.55~57 两数之和、判定是否互为字符重排、存在重复元素]
数据结构·散列表
稚辉君.MCA_P8_Java2 小时前
Gemini永久会员 go数组中最大异或值
数据结构·后端·算法·golang·哈希算法
会员果汁2 小时前
双向链式队列-C语言
c语言·数据结构
AI科技星3 小时前
张祥前统一场论:引力场与磁矢势的关联,反引力场生成及拉格朗日点解析(网友问题解答)
开发语言·数据结构·经验分享·线性代数·算法
C雨后彩虹3 小时前
最少交换次数
java·数据结构·算法·华为·面试
-森屿安年-3 小时前
二叉平衡树的实现
开发语言·数据结构·c++
稚辉君.MCA_P8_Java3 小时前
Gemini永久会员 Go 返回最长有效子串长度
数据结构·后端·算法·golang
TL滕4 小时前
从0开始学算法——第五天(初级排序算法)
数据结构·笔记·学习·算法·排序算法
Ayanami_Reii4 小时前
进阶数据结构应用-线段树扫描线
数据结构·算法·线段树·树状数组·离散化·fenwick tree·线段树扫描线