数据结构:堆的三部曲(二)top K问题

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

一.top k问题的应用本质解析

top k问题解决的是获取前几个最值的问题。
我们知道堆的功能主要是选数,选出最大值或者最小值。那么我们每次获取堆顶元素后,再将剩余元素调整成堆,就可以选出次大的数,如果我们只想要前k个最大值或者最小值,就只需要获取堆顶元素k次,调整k次。比如王者荣耀中的国服榜单,需要的是这个英雄的前十名,我们只需要获取前10名即可。

学习了堆的实现,我们对于比较少的数据可以采用建堆一直push的方式,再取堆顶元素再pop从而找到次大值的方法,循环k次上述操作即可实现。但是如果数据非常多,那么malloc申请空间会失败,此时堆无法建立开辟,此时我们应该如何解决呢?

以找前k个最大值为例:
上面的问题是因为内存不足,为了解决这个问题,这里我们可以从文件中读取k个数据并且建一个小堆,然后再依次处理剩余的元素。

为什么要建小堆?
这里很多人可能第一印象就是建立大堆,从而选出前k个最大值,但是我们想一个问题,如果最大的值在前k个数中,那么最大值就会在堆顶,那么其他k-1个需要找的值就都会比堆顶小,导致无法入堆。
因此我们需要建小堆,如果比堆顶的元素大,那么就和堆顶的元素交换,然后再调整,这样的话最大值就会沉入堆底,直到前k个最大的数都进入堆中。

总结:前k个最小值建大堆,前k个最大值建小堆

我们通过以下的案例来学习解决这一问题。

二.top K问题使用案例——从100亿整型的文件中找出前5个最大值

由一的分析我们可以得知需要建小堆。

我们首先先创建足够多的整形随机数,并保存在文件中。为了验证我们的top k是否正确,我们将随机值取模于一个10000000,保证数据都在这个范围内,然后我们自己手动插入几个“探子”,我们在该txt文件中改变几个值的大小为超过10000000,这样我们就可以通过这几个“探子”是否被找到从而验证是否正确。

在读取前k个元素时顺便建堆,我们采取向上调整建堆的方法。
向上调整建堆:模拟堆的插入的思想,我们使用向上调整算法来建堆(详情请看上篇:堆的实现)

1.建堆

1.1过程分析

由于向上调整算法和向下调整算法的前提是插入前仍然是堆,插入后改变了堆的性质。因此首先将第一个元素看作堆,然后后面的元素模拟依次入堆的操作,也就是将后面元素的下标依次作为最后一个节点的坐标传入向上调整算法函数之中,这样的话每次向上调整传入下标前面的值为堆,从而满足前提条件。

1.2过程图模拟

数据结构:堆的三部曲(二)top K问题,数据结构,开发语言,c语言,算法,学习,程序人生,交友
数据结构:堆的三部曲(二)top K问题,数据结构,开发语言,c语言,算法,学习,程序人生,交友

1.3向上调整算法代码

void AdjustUp(Hpdatatype* a, int child)
{
	int parent = (child - 1) / 2;
	while (child > 0)
	{
		if (a[child] < a[parent])
		{
			Swap(&a[child], &a[parent]);
			child = parent;
			parent = (child - 1) / 2;
		}
		else
		{
			break;
		}
	}
}

1.4建堆代码

	int* heap = (int*)malloc(sizeof(int) * k);
	for (int i = 0; i < k; i++)
	{
		fscanf(fout, "%d", &heap[i]);
		//从文件中读取数据存储到heap中去
		AdjustUp(heap, i);
		//开始调整
	}

2.处理文件中剩余剩余元素

2.1过程分析

依次读取文件中的数据,并存储在变量tmp之中,再将其和和堆顶元素比较,比堆顶大,就和堆顶交换(堆顶是最小值,如果它比tmp小,就证明它不是我们需要找的元素),然后再向下调整,如果比堆顶元素小,则不需要入堆,。直到文件读取结束。

2.2过程图示例

和4比较,不需要入堆,如图:
数据结构:堆的三部曲(二)top K问题,数据结构,开发语言,c语言,算法,学习,程序人生,交友
和20比较,需要入堆,如图:

数据结构:堆的三部曲(二)top K问题,数据结构,开发语言,c语言,算法,学习,程序人生,交友

2.3向下调整算法代码

void AdjustDown(Hpdatatype* a, int size, int parent)
{
	int child = parent * 2 + 1;
	while (child < size)
	{
		if (child + 1 < size && a[child] > a[child + 1])
		{
			child++;
		}
		if (a[child] < a[parent])
		{
			Swap(&a[child], &a[parent]);
			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
			break;
		}
	}
}

2.4处理后续元素代码

	int tmp = 0;//存储读取的值
	while (fscanf(fout, "%d", &tmp) != EOF)
	{
		if (tmp > heap[0])
		{
			Swap(&tmp, &heap[0]);
			AdjustDown(heap, k, 0);
		}
	}

三.附录源码

向上调整算法代码:

void AdjustUp(Hpdatatype* a, int child)
{
	int parent = (child - 1) / 2;
	while (child > 0)
	{
		if (a[child] < a[parent])
		{
			Swap(&a[child], &a[parent]);
			child = parent;
			parent = (child - 1) / 2;
		}
		else
		{
			break;
		}
	}
}

向下调整算法代码:

void AdjustDown(Hpdatatype* a, int size, int parent)
{
	int child = parent * 2 + 1;
	while (child < size)
	{
		if (child + 1 < size && 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 creatInform()
{
	int n = 10000000;
	srand(time(0));
	const char* file = "data.txt";
	FILE* fin = fopen(file, "w");
	if (fin == NULL)
	{
		perror("fopen error");
		return;
	}

	for (int i = 0; i < n; ++i)
	{
		int x = (rand() + i) % 10000000;
		fprintf(fin, "%d\n", x);
	}

	fclose(fin);
}

测试代码如下:

void testTopK(const char* file, int k)
{
	FILE* fout = fopen(file, "r");
	if (fout == NULL)
	{
		perror("fopen error");
		return;
	}

	int* heap = (int*)malloc(sizeof(int) * k);
	//建堆
	for (int i = 0; i < k; i++)
	{
		fscanf(fout, "%d", &heap[i]);
		AdjustUp(heap, i);
	}

	int tmp = 0;
	while (fscanf(fout, "%d", &tmp) != EOF)
	{
		if (tmp > heap[0])
		{
			Swap(&tmp, &heap[0]);
			AdjustDown(heap, k, 0);
		}
	}

	fclose(fout);
	
	for (int i = 0; i < k; i++)
	{
		printf("%d ", heap[i]);
	}
}

以上是本次所有内容,谢谢观看。文章来源地址https://www.toymoban.com/news/detail-787586.html

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

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

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

相关文章

  • Java版人脸跟踪三部曲之三:编码实战

    这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos 作为《Java版人脸跟踪三部曲》系列的终篇,本文会与大家一起写出完整的人脸跟踪应用代码 前文《开发设计》中,已经对人脸跟踪的核心技术、应用主流程、异常处理等方方面面做了详细设计,建

    2024年02月12日
    浏览(27)
  • JavaCV人脸识别三部曲之三:识别和预览

    这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos 《视频中的人脸保存为图片》 《训练》 《识别和预览》 作为《JavaCV人脸识别三部曲》的终篇,今天咱们要开发一个实用的功能:有人出现在摄像头中时,应用程序在预览窗口标注出此人的身份,效

    2024年02月11日
    浏览(31)
  • Go语言基准测试(benchmark)三部曲之一:基础篇

    这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos Go的标准库内置的testing框架提供了基准测试(benchmark)功能,可以用来验证本地方法在串行或者并行执行时的基准表现,帮助开发者了解代码的真实性能情况,例如一个方法执行一次的平均耗时,还能

    2024年02月06日
    浏览(38)
  • vscode上的git三部曲+git pull操作

    git三部曲:git add .、git commit -m \\\'\\\'、git push,命令在连接远程仓库的本地仓库路径下的终端执行。 vscode上的可视化操作如下:  1、对仓库里的文件做更改,让仓库操作的地方有变化。 2、 点击+号,让文件进入缓存,此步骤相当于终端执行命令git add .  3、在这里输入信息并点击

    2024年02月11日
    浏览(29)
  • Java版人脸跟踪三部曲之二:开发设计

    如何开发Java版人脸跟踪应用?本篇给出了设计大纲,并解释了相关的重要知识点 这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos 本篇是《Java版人脸跟踪三部曲》系列的第二篇,前文体验了人脸跟踪的效果,想要编码实现这样的效果,咱们需要做

    2024年02月12日
    浏览(28)
  • 【C++系列P4】‘类与对象‘-三部曲——[类](2/3)

     前言 大家好吖,欢迎来到 YY 滴 C++系列 ,热烈欢迎! 【 \\\'类与对象\\\'-三部曲】的大纲主要内容如下 : 如标题所示,本章是【 \\\'类与对象\\\'-三部曲】三章中的第二章节—— 类章节 ,主要内容如下: 目录 一.类 1.类的组成与计算类的大小(含结构体内存对齐规则) 二. 空类的大小

    2024年02月08日
    浏览(31)
  • Go语言基准测试(benchmark)三部曲之三:提高篇

    这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos -《Go语言基准测试(benchmark)三部曲》已近尾声,经历了《基础篇》和《内存篇》的实战演练,相信您已熟练掌握了基准测试的常规操作以及各种参数的用法,现在可以学习一些进阶版的技能了,在面

    2024年02月06日
    浏览(31)
  • 大模型 Dalle2 学习三部曲(二)clip学习

    clip论文比较长48页,但是clip模型本身又比较简单,效果又奇好,正所谓大道至简,我们来学习一下clip论文中的一些技巧,可以让我们快速加深对clip模型的理解,以及大模型对推荐带来革命性的变化。 首选我们来看看clip的结构,如图clip结构比较直观,训练的时候把文本描述

    2024年02月09日
    浏览(29)
  • 文生图大模型三部曲:DDPM、LDM、SD 详细讲解!

    跨模态大模型是指能够在不同感官模态(如视觉、语言、音频等)之间进行信息转换的大规模语言模型。当前图文跨模态大模型主要有: 文生图大模型:如 Stable Diffusion系列 、DALL-E系列、Imagen等 图文匹配大模型:如CLIP、Chinese CLIP、BridgeTower等 今天主要讨论 Stable Diffusion ,首先

    2024年04月10日
    浏览(30)
  • 【C++系列P5】‘类与对象‘-三部曲——[对象&特殊成员](3/3)

     前言 大家好吖,欢迎来到 YY 滴 C++系列 ,热烈欢迎! 【 \\\'类与对象\\\'-三部曲】的大纲主要内容如下 : 如标题所示,本章是【 \\\'类与对象\\\'-三部曲】三章中的第三章节——对象成员章节,主要内容如下: 目录 一.const成员/成员函数 一.用const修饰this指针的好处——含权限知识点

    2024年02月06日
    浏览(34)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包