数据结构:Heap堆应用(堆排序,TOP-K问题)手把手带你入门数据结构~

news2024/9/26 15:04:40

文章目录

  • 前言
  • 一、堆排序
    • 1. 数据入堆
    • 2. 堆排序
    • 3. 时间复杂度
      • (1)冒泡排序时间复杂度
      • (2)向上调整建堆的时间复杂度
      • (3)向下调整建堆的时间复杂度
    • 4. 堆排序总结
  • 二、TOP-K问题
    • 1. TOP-K问题背景
    • 2. TOP-K问题解决方法
    • 3. 创建庞大的数据
    • 4. TOP-K问题的解决
  • 总结


前言

在这里插入图片描述

在学习了堆之后,我们一起来看一看堆的应用~


一、堆排序

1. 数据入堆

在这里插入图片描述
想要让一组数据进行堆排序,我们来想一想,像下面这一组数据要怎么建堆?
在这里插入图片描述
这是一个乱序的数组,将每一个数组的元素取出来向上调整建堆。

在这里插入图片描述
排成如下图所示的样子,就完成数据入堆了~
在这里插入图片描述
在这里插入图片描述

for (int i = 0; i < n; i++)
{
	AdjustUp(arr, i);
}

2. 堆排序

现在我们已经有了一个小根堆,那么我们就可以将堆排成降序结构。

小根堆排降序
大根堆排升序

在这里插入图片描述

//循环将堆顶数据跟最后位置(会变化,每次减少一个数据)的数据进行交换
int end = n - 1;
while (end > 0)
{
	Swap(&arr[0], &arr[end]);
	AdjustDown(arr, 0, end);
	end--;
}
void AdjustDown(HPDataType* arr, int parent, int n)
{
	int child = parent * 2 + 1;//左孩子
	//while (parent < n)
	while (child < n)
	{
		//小堆:找左右孩子中找最小的
		//大堆:找左右孩子中找大的
		if (child + 1 < n && arr[child] > arr[child + 1])
		{
			child++;
		}
		if (arr[child] < arr[parent])
		{
			Swap(&arr[child], &arr[parent]);
			parent = child;
			child = parent * 2 + 1;

		}
		else
		{
			break;
		}
	}
}
void AdjustUp(HPDataType* arr, int child)
{
	int parent = (child - 1) / 2;

	while (child > 0)//不需要等于,child只要走到根节点的位置,根节点没有父节点不需要交换
	{
		//建大堆,>
		//建小堆,<
		if (arr[child] < arr[parent])
		{
			Swap(&arr[parent], &arr[child]);
			child = parent;
			parent = (child - 1) / 2;
		}
		else
		{
			break;
		}
	}

}

3. 时间复杂度

(1)冒泡排序时间复杂度

时间复杂度为O(n^2)

//冒泡排序
//时间复杂度:0(N^2)
void BubbleSort(int* arr, int n)
{
	for (int i = 0; i < n; i++)
	{
		int exchange = 0;
		for (int j = 0; j < n - i - 1; j++)
		{
			//升序
			if (arr[j] > arr[j + 1])
			{
				exchange = 1;
				Swap(&arr[j], &arr[j + 1]);
			}
		}
		if (exchange == 0)
		{
			break;
		}
	}
}

(2)向上调整建堆的时间复杂度

在这里插入图片描述
从这张图可以简单分析得知,向上调整的时间复杂度是log n,而循环有n次,因此时间复杂度为log n。

for (int i = 0; i < n; i++)
{
	AdjustUp(arr, i);
}

那么堆排序和冒泡排序的差距有多大呢?我们看下面这张图。
在这里插入图片描述
因此堆排序的效率高。

下面我们严谨证明一下向下调整算法建堆的时间复杂度:
在这里插入图片描述


(3)向下调整建堆的时间复杂度

那么向下调整怎么建堆呢?
在这里插入图片描述

向下调整算法有⼀个前提:左右⼦树必须是⼀个堆,才能调整。

向下调整算法
• 将堆顶元素与堆中最后⼀个元素进⾏交换
• 删除堆中最后⼀个元素
• 将堆顶元素向下调整到满⾜堆特性为⽌
在这里插入图片描述

//向下调整算法建堆
for (int i = (n - 1 - 1) / 2; i >= 0; i--)
{
	AdjustDown(arr, i, n);
}

接下来我们来推理一下向下调整建堆的时间复杂度。

在这里插入图片描述
所以用向下调整建堆的方法更优
在这里插入图片描述

因此堆排序的时间复杂度为 O(n* log n)~


4. 堆排序总结

//堆排序
//空间复杂度为0(1)
//时间复杂度为O(n*logn)
void HeapSort(int* arr, int n)
{
	//建堆
	//升序---大堆
	//降序----小堆


	//for (int i = 0; i < n; i++)
	//{
	//	AdjustUp(arr, i);
	//}

	//向下调整算法建堆
	for (int i = (n - 1 - 1) / 2; i >= 0; i--)
	{
		AdjustDown(arr, i, n);
	}

	//循环将堆顶数据跟最后位置(会变化,每次减少一个数据)的数据进行交换
	int end = n - 1;
	while (end > 0)
	{
		Swap(&arr[0], &arr[end]);
		AdjustDown(arr, 0, end);
		end--;
	}
}

二、TOP-K问题

1. TOP-K问题背景

TOP-K问题:即求数据结合中前K个最⼤的元素或者最⼩的元素,⼀般情况下数据量都⽐较⼤。

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

对于Top-K问题,能想到的最简单直接的⽅式就是排序,但是:如果数据量⾮常⼤,排序就不太可取了(可能数据都不能⼀下⼦全部加载到内存中)。


2. TOP-K问题解决方法

1)⽤数据集合中前K个元素来建堆.

前k个最⼤的元素,则建⼩堆
前k个最⼩的元素,则建⼤堆

2)⽤剩余的N-K个元素依次与堆顶元素来⽐较,不满⾜则替换堆顶元素
将剩余N-K个元素依次与堆顶元素⽐完之后,堆中剩余的K个元素就是所求的前K个最⼩或者最⼤的元素.

在这里插入图片描述

3. 创建庞大的数据

将数据写到文件中,为了方便观察,我们可以手动改几个数据

void CreateNDate()
{
	// 造数据
	int n = 100000;
	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) % 1000000;
		fprintf(fin, "%d\n", x);
	}
	fclose(fin);
}

4. TOP-K问题的解决

void TOPk()
{
	int k = 0;
	printf("请输入k:");
	scanf("%d", &k);

	const char* file = "data.txt";
	FILE* fout = fopen(file, "r");
	if (fout == NULL)
	{
		perror("fopen fail!");
		exit(1);
	}
	int* minHeap = (int*)malloc(k * sizeof(int));
	if (minHeap == NULL)
	{
		perror("malloc fail!");
		exit(2);
	}

	//从文件中读取前K个数据
	for (int i = 0; i < k; i++)
	{
		fscanf(fout, "%d", &minHeap[i]);
	}

	//建堆---小堆
	for (int i = (k - 1 - 1) / 2; i >= 0; i--)
	{
		AdjustDown(minHeap, i, k);
	}

	int x = 0;
	while (fscanf(fout, "%d", &x) != EOF)
	{
		//读取到的数据跟堆顶的数据进行比较
		//比堆顶值大,交换入堆
		if (x > minHeap[0])
		{
			minHeap[0] = x;
			AdjustDown(minHeap, 0, k);
		}
	}

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

	fclose(fout);
}

总结

通过上述讲解,相信大家对堆的经典问题已经有了大概的了解,观众老爷们下去要多多练习,感谢支持!

真相永远只有一个!

在这里插入图片描述

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

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

相关文章

【日记】感觉自己已经魔怔了(817 字)

正文 下午装档案的时候&#xff0c;无意间朝外看了一眼&#xff0c;发现自己视力衰退了好多。感觉两只眼睛都有散光了&#xff0c;看东西有重影。有些担心。 兄长血检报告出来了&#xff0c;血红蛋白高&#xff0c;肌酐低。尿酸倒是正常了&#xff0c;但总体还是偏高。我觉得好…

408解题小助手—文心智能体

体验链接&#xff1a;408解题小助手 问题&#xff1a; 个字符有如下 种编码方案&#xff0c;不是前缀编码的是 A. 01 0000 0001 001 1 B. 011, 000, 001, 010, 1 C. 000, 001, 010, 011, 100 D. 0, 100, 110, 1110, 1100 回答&#xff1a; 不是前缀编码的是选项 D&#xff1a;0…

Java项目: 基于SpringBoot+mybatis+maven实现的智能推荐卫生健康系统分前后台(含源码+数据库+开题报告+任务书+毕业论文)

一、项目简介 本项目是一套基于SpringBootmybatismaven实现的智能推荐卫生健康系统 包含&#xff1a;项目源码、数据库脚本等&#xff0c;该项目附带全部源码可作为毕设使用。 项目都经过严格调试&#xff0c;eclipse或者idea 确保可以运行&#xff01; 该系统功能完善、界面美…

C++ —— 关于list

目录 链接 前言 1. 迭代器浅解 2. 接口 2.1 构造函数 2.2 push_back 2.3 emplace_back 2.4 insert 2.5 erase 2.6 reverse 2.7 sort 2.8 merge 2.9 unique 2.10 splice 链接 cplusplus.com/reference/list/list/?kwlisthttps://cplusplus.com/reference/list/list…

MSF工具使用教程

Metasploit 简介 Metasploit 是一个漏洞框架&#xff0c;拥有超过 1700 个漏洞利用程序&#xff0c;大大简化了渗透测试的工作&#xff0c;同时具有模块化的体系结构&#xff0c;渗透测试人员可以很方便的添加或修改exploit。 安装及维护 安装 使用 Rapid7 的一套快速安装项…

js逆向--某建筑市场公共监管服务平台

js逆向--某建筑市场公共监管服务平台 一、抓包二、断点调试三、写代码一、抓包 很容易找到数据接口,发现响应加密了。 二、断点调试 打开源代码/来源界面,下一个XHR断点。 点击翻页,发现代码断住了。 发现到下图中的位置时,明文出现了。 点击上图中的图标进入b方法,找…

数据集-目标检测系列-自行车检测数据集 bike>> DataBall

数据集-目标检测系列-自行车检测数据集 >> DataBall 数据集-目标检测系列-自行车检测数据集 数据量&#xff1a;1W 数据项目地址&#xff1a; gitcode: https://gitcode.com/DataBall/DataBall-detections-100s/overview github: https://github.com/TechLinkX/Data…

mybatisplus 分页查询 使用ORDER BY 时可能数据重复

原始方法&#xff1a; 第一页数据&#xff1a; 第二页数据&#xff1a; 解决方案&#xff1a; 后面在添加一个唯一键 id

2024年信息学奥赛CSP-J初赛真题详细分析

CSP-J 2024 入门组初赛第一轮初赛试题及答案解析 一、 单项选择题&#xff08;共15题&#xff0c;每题2分&#xff0c;共计30分&#xff1a;每题有且仅有一个正确选项&#xff09; 1 32 位 int 类型的存储范围是&#xff08; &#xff09; A -2147483647 ~ 2147483647B -214…

OpenCV图像文件读写(1)检查 OpenCV 是否支持某种图像格式的读取功能函数haveImageReader()的使用

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 haveImageReader 函数通常用于检查 OpenCV 是否支持某种图像格式的读取功能。在 OpenCV 中&#xff0c;haveImageReader 函数可以帮助确定是否可…

【探索智谱AI的CogVideoX:视频生成的新前沿】

2024年8月6日&#xff0c;智谱AI宣布其开源视频生成模型CogVideoX&#xff0c;激发了开发者的创造力和对新技术的期待。 一、CogVideoX模型概述 CogVideoX 是一款先进的视频生成工具&#xff0c;可基于最长 226 个 token 的提示生成视频&#xff0c;时长可达 6 秒&#xff0c;…

美化网页,特效

当阅读博客园的文章时&#xff0c;经常看到精美的特效 博客园美化 - 凌云 - 博客园 (cnblogs.com) 简直不要太好看 自己写了一个前后端分离的网站后&#xff0c;想着应用这些特效&#xff0c;毕竟别人看到特效后逼格还是挺高的 于是&#xff0c;我F12把代码拿了下来 【手动狗…

算法记录——树

二叉树 3.1二叉树的最大深度 思路&#xff1a;二叉树的最大深度 根节点的最大高度。因此本题可以转换为求二叉树的最大高度。 而求高度的时候应该采用后序遍历。遍历顺序为&#xff1a;左右中。每次遍历的节点按后序遍历顺序&#xff0c;先收集左右孩子的最大高度&#xff0c;…

SpringBoot Validation不生效该怎么办?

SpringBoot Validation不生效该怎么办&#xff1f; 确认maven依赖查看依赖关系并处理验证&#xff1a;校验生效&#xff0c;成功反思 能问出这个问题说明你已经使用了Null、NotEmpty等等等校验注解&#xff0c;但是没有生效&#xff0c;我也出现过这种情况&#xff0c;请看我修…

解析!文档扫描 SDK 中的高级图像处理技术

随着世界数字化&#xff0c;文档扫描已成为现代商业运营的关键&#xff0c;它使文档的存储、访问和管理更加便捷。然而&#xff0c;扫描图像的质量对于这些数字档案的有效性至关重要。高质量的扫描可确保文本清晰、数据准确捕获并且信息易于检索。 另一方面&#xff0c;质量差…

几乎跪着读完这本Transformer经典神书,震撼到爆!!

本书的目标是让您能够构建自己的语言应用程序。 涵盖了NLP中transformers的所有主要应用&#xff0c;每一章(除了少数例外)专门针对一个任务&#xff0c;结合一个实际的用例和数据集。每一章还介绍了一些额外的概念。 以下是我们将涉及的任务和主题的一个高级概述: 第一章&am…

学生护眼台灯哪个品牌比较好?性价比高的学生用台灯推荐

如今&#xff0c;随着近视在儿童中的普及率日益上升&#xff0c;这与学习压力以及频繁使用电子产品密切相关。一旦孩子患上近视&#xff0c;如果不注意用眼卫生&#xff0c;近视加深的速度会非常快&#xff0c;导致镜片越来越厚。因此&#xff0c;保持良好的用眼习惯对于预防近…

sass安装问题

首先直接安装 npm i sass 报错python&#xff0c;如上图 之后百度的方法&#xff0c;清除缓存再次安装&#xff08;删掉node_moudle&#xff09;,显示安装成功&#xff0c;但是运行还是会报错找不到sass模块 之后又百度了方法&#xff0c;要先安装cnpm&#xff0c;通过cnpm安装…

腾讯通用户必看:低成本平滑迁移方案,兼容Linux与移动端

一、腾讯通停更后用户面临的核心问题 自从腾讯通&#xff08;RTX&#xff09;停止更新并下架官网&#xff0c;许多用户失去了更新和技术支持的途径&#xff0c;同时不得不面对以下几大难题&#xff1a; 无法在移动端和Linux系统上使用&#xff1a;腾讯通仅支持Windows和Mac系…

HyperWorks实体网格划分

实体网格剖分 在 HyperMesh 中&#xff0c;使用 Solid Map 功能进行实体网格剖分。该面板如下图所示&#xff1a; 图 4-4 Solid Map 面板 通过 Solid Map Panel 进行实体网格剖分: • 通过主菜单栏选择 3D 页面 > solid map 。 • 通过下拉式菜单选择 Mesh > create…