数据结构—Top K问题

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/z_x_m_m_q/article/details/82389347

提示:这里解决 top K 问题是基于堆数据结构下的,对这块还有问题的可以点以下链接:

https://blog.csdn.net/z_x_m_m_q/article/details/82320357

Top K问题:

Topk问题是一个经典的海量数据处理问题, 在海量数据中找出出现频率最高的前k个数,或者从海量数据中找出最大的前k个数,这类问题通常被称为Top K问题

比如,热搜上每天更新出的排行前10的热门搜索信息,陕西人最爱吃的水果种类等,都可以使用topK问题来解决

海量数据:

海量数据拥有的一大特点就是数据量比较大, 一般情况下内存空间是不足以一次性来存储的,或者处理海量数据是往往有空间上的限制

例如:面试官给你100W个数据,请找出其中最大的前K个数,并且现在仅仅有1M的空间?

在32位操作系统中,默认每个数据为4字节,很显然 1M 的空间是存放不了要处理的目标数据

算法思想:

从大量数据中找出前 K 个最大数为例来说明:

首先以给定数据中的前 K 个数建立小堆,然后从 K+1 个数据开始与堆顶元素作比较,小于或等于堆顶元素时,保持建立的小堆不变;大于堆顶元素时,将该数据与堆顶元素交换,此时有可能破坏了小堆的有序性,需要从堆顶元素开始来一次向下调整使堆恢复成小堆

算法代码:

 这里我提供一个 main 函数开始的完整的代码,还有部分注释,供大家参考

#include"pch.h"
#include<stdio.h>
#include<malloc.h>
#include<stdlib.h>
#include<time.h>

void Swap(int* x,int* y)  //交换函数,建议使用这种方式交换
{
	int tmp = *x;
	*x = *y;
	*y = tmp;
}

void HeapAdjustDown(int* a,int n,int root)  //堆的向下调整函数
{
	int parent = root;
	int child = 2 * parent + 1;

	while (child < n) {
		if (child+1 < n && a[child+1] < a[child])
			++child;

		if (a[child] < a[parent])
			Swap(&a[child], &a[parent]);
		else
			break;

		parent = child;
		child = 2 * parent + 1;
	}
}

void Top_K(int* a,int n,int k)
{
	int i = 0;

	int* hp = (int*)malloc(sizeof(int)*k);  //用于始终存储堆中的 K 个数,记得释放空间
	for (i = 0;i < k;++i)
		hp[i] = a[i];

	for (i = (k-2)/2;i >= 0;--i)  //建堆
	{
		HeapAdjustDown(hp,k,i);
	}

	for (i = k;i < n;++i)  //从 K+1 个数开始与堆顶元素一一比较
	{
		if (a[i] > hp[0])  //a[0]:堆顶元素
		{
			hp[0] = a[i];
			HeapAdjustDown(hp, k, 0);
		}
	}

	for (i = 0;i < k;++i)  //简单的看下输出结果
	{
		printf("%d ",hp[i]);
	}

	free(hp);
	hp = NULL;
}

int main()
{
	int i = 0;
	int a[1024];

	srand((unsigned)time(NULL));

	for (i = 0;i < 1024;++i)
	{
		a[i] = rand();
	}

	Top_K(a,sizeof(a)/sizeof(a[0]),8);

	return 0;
}

结果展示: 

 

上面从大量数据中找出的最大的 8 个数显然满足小堆的性质。 

时间复杂度: 

基于堆数据结构下的 Top K 问题时间复杂度为:O(N\lg K),这是很显然的 

猜你喜欢

转载自blog.csdn.net/z_x_m_m_q/article/details/82389347
今日推荐