堆的应用:堆排序和TOP-K问题

news2024/11/27 9:33:14

上次才讲完堆的相关问题:二叉树顺序结构与堆的概念及性质(c语言实现堆
那今天就接着来进行堆的主要两方面的应用:堆排序和TOP-K问题


文章目录

  • 1.堆排序
    • 1.1概念、思路及代码
    • 1.2改良代码(最初建立大堆用AdjustDow)
  • 2. TOP-K问题


1.堆排序

1.1概念、思路及代码

堆排序即利用堆的思想来进行排序,总共分为两个步骤:

  1. 建立堆
  • 升序:建立大堆
  • 降序:建立小堆
  1. 利用堆删除思想来进行排序:堆顶元素是当前堆中的最大值(大堆)或最小值(小堆),将堆顶元素与堆中最后一个元素交换,然后将剩余元素重新调整成堆,再取出堆顶元素。重复上述步骤,直到所有元素都被取出,即完成了排序
#define _CRT_SECURE_NO_WARNINGS 1
#include"Heap.h"

void Swap(HPDataType* p1, HPDataType* p2)
{
	HPDataType tmp = *p1;
	*p1 = *p2;
	*p2 = tmp;
}

void AdjustUp(HPDataType* a, int child)
{
	int father = (child - 1) / 2;
	while (child > 0)
	{
		if (a[child] > a[father])
		{
			Swap(&a[child], &a[father]);
			//更新下标
			child = father;
			father = (father - 1) / 2;
		}
		else
		{
			break;//一旦符合小堆了,就直接退出
		}
	}
}

void AdjustDown(HPDataType* a, int n, int father)
{
	int child = father * 2 + 1;//假设左孩子大
	while (child < n)
	{
		if (child + 1 < n && a[child] < a[child + 1])
		{
			child++;
		}
		if (a[child] > a[father])
		{
			Swap(&a[child], &a[father]);
			father = child;
			child = father * 2 + 1;
		}
		else
		{
			break;
		}
	}
}

void HeapSort(int* arr, int n)//升序
{
	//先建大堆
	for (int i = 0; i < n; i++)
	{
		AdjustUp(arr, i);
	}
	int a = n - 1;
	while (a > 0)
	{
		//此时最大的是堆顶,堆顶跟最后一个交换
		Swap(&arr[0], &arr[a]);
		//现在最大的已经在最后了,不考虑它,把新塔顶降下来,重新编程大堆
		AdjustDown(arr, a, 0);
		a--;
	}

}

int main()
{
	int arr[]= { 4,6,2,1,5,8,2,9 };
	for (int i = 0; i < sizeof(arr) / sizeof(int); i++)
	{
		printf("%d ", arr[i]);
	}
	printf("\n");
	HeapSort(arr, sizeof(arr) / sizeof(int));
	for (int i = 0; i < sizeof(arr) / sizeof(int); i++)
	{
		printf("%d ", arr[i]);
	}
}

结果:

请添加图片描述

1.2改良代码(最初建立大堆用AdjustDow)

仅仅该那一部分:

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, n, i);
	}

	int a = n - 1;
	while (a > 0)
	{
		//此时最大的是堆顶,堆顶跟最后一个交换
		Swap(&arr[0], &arr[a]);
		//现在最大的已经在最后了,不考虑它,把新塔顶降下来,重新编程大堆
		AdjustDown(arr, a, 0);
		a--;
	}

}

对于一个具有n个节点的完全二叉树来说,最后一个非叶子节点的下标是(n-1-1)/2,也就是说,从最后一个非叶子节点开始,依次向上调整每个节点,就可以建立一个大堆

相比于向上调整,向下调整的好处:时间复杂度低

  • 向下调整的时间复杂度是O(n),而向上调整的时间复杂度是O(nlogn)

建堆的时间复杂度为 O(n),排序过程的时间复杂度为 O(n log n)(建堆的时间复杂度为 O(n),而对堆进行排序的过程中,需要进行 n-1 次堆调整操作,每次堆调整的时间复杂度为 O(log n)。因此,排序过程的时间复杂度为 O(n log n))


2. TOP-K问题

TOP-K问题:求数据结合中前K个最大的元素或者最小的元素,一般情况下数据量都比较大

对于Top-K问题,能想到的最简单直接的方式就是排序,然后直接取。 但是:如果数据量非常大,排序就不 太可取了,最佳的方式就是用堆来解决,基本思路如下:

  1. 用数据集合中前K个元素来建堆
    • 要找前k个最大的元素,则建小堆
    • 要找前k个最小的元素,则建大堆
  1. 用剩余的元素依次与堆顶元素来比较,不满足则替换堆顶元素
    • 要找前k个最大的元素:但凡剩余的有比小堆堆顶大的就进入到堆里面,然后向下沉;如果建立大堆有可能一个都进不来。
    • 找前k个最小的也同理
void CreateData()//用来创建有随机数的文件的进行检测
{
	int N = 1000;
	srand(time(0));
	FILE* f = fopen("data.txt", "w");

	for (int i = 0; i < N; i++)
	{
		int a = (rand()) % 10000;
		fprintf(f,"%d\n", a);
	}
	fclose(f);

}

void PrintTopK(int k)//前k个大的
{
	//先读文件
	FILE* fout = fopen("data.txt", "r");
	if (fout == NULL)
	{
		perror("fopen file");
		return -1;
	}
	int* a = (int*)malloc(sizeof(int) * k);
	for (int i = 0; i < k; i++)//建立元素k的小堆
	{
		fscanf(fout, "%d", &a[i]);//把文件里的前k个数字写入数组里
		AdjustUp(a, k);
	}
	//如果有比堆顶大的,就进来
	int n = 0;
	while (fscanf(fout, "%d", &n) != EOF)//读到文件读完就停止
	{
		if (n > a[0])
		{
			a[0] = n;
			AdjustDown(a, k, 0);
		}
	}
	for (int i = 0; i < k; i++)
	{
		printf("%d ", a[i]);
	}
	printf("\n");
	fclose(fout);
}

int main()
{
	PrintTopK(5);
	return 0;
}

结果如下:

请添加图片描述


那这次堆的两大应用就先到这里啦,到此二叉树顺序结构部分的知识也已经分享完毕了。感谢大家的支持,希望能帮助到大家!!!

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

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

相关文章

个人简历范本(精选5篇)

HR浏览一份简历也就25秒左右&#xff0c;如果你连「好简历」都没有&#xff0c;怎么能找到好工作呢&#xff1f; 如果你不懂得如何在简历上展示自己&#xff0c;或者觉得怎么改简历都不出彩&#xff0c;那请你一定仔细读完。 个人求职简历第 1 篇 男 22 本科 AI简历 市场营…

听GPT 讲Rust源代码--library/alloc(2)

File: rust/library/alloc/src/vec/mod.rs 在Rust源代码中&#xff0c;rust/library/alloc/src/vec/mod.rs这个文件是Rust标准库中的Vec类型的实现文件。Vec是一个动态大小的数组类型&#xff0c;在内存中以连续的方式存储其元素。 具体来说&#xff0c;mod.rs文件中定义了以下…

基于RetinaFace+Jetson Nano的智能门锁系统——第一篇(烧录系统)

文章目录 设备1.首先在PC端安装VMware虚拟机和Ubuntu182.安装VMware Tools3.安装SDK Manager 设备 Jetson NanoMicro-USB - USB-A电源线HDMI线屏幕PC一台 1.首先在PC端安装VMware虚拟机和Ubuntu18 VMware下载地址&#xff1a;https://www.vmware.com/cn/products/workstatio…

Node.js+Express 路由配置,实现接口分类管理

首先创建一个路由目录及文件 routes/user.js代码 const express require(express); const router express.Router(); // 使用express提供的router对象 const db require(../dbserver/mysql);router.get(/api/user, (req, res) > {const sqlStr SELECT * FROM sys_user;…

【算法】NOIP2017奶酪(搜索)

题目描述 现有一块大奶酪&#xff0c;它的高度为 h&#xff0c;它的长度和宽度我们可以认为是无限大的&#xff0c;奶酪中间有许多半径相同的球形空洞。我们可以在这块奶酪中建立空间坐标系&#xff0c; 在坐标系中&#xff0c;奶酪的下表面为 z 0&#xff0c;奶酪的上表面为…

odoo17 | 创建一个新应用程序

前言 本章的目的是为创建一个全新的Odoo模块奠定基础。 我们将从头开始&#xff0c;以使我们的模块被Odoo识别所需的最低限度。 在接下来的章节中&#xff0c;我们将逐步添加功能以构建一个真实的业务案例。 教程 假设我门需要在odoo上开发一个新app模块例如房地产广告模块。…

详解Vue3中的事件监听方式

本文主要介绍Vue3中的事件监听方式。 目录 一、v-on指令二、使用符号简写三、事件修饰符四、动态事件名五、常见的监听事件六、自定义事件 在Vue3中&#xff0c;事件监听的方式与Vue2有一些不同。 下面是Vue3中事件监听方式的详细介绍&#xff1a; 一、v-on指令 Vue3中仍然使…

【java爬虫】使用element-plus进行个股详细数据分页展示

前言 前面的文章我们讲述了获取详细个股数据的方法&#xff0c;并且使用echarts对个股的价格走势图进行了展示&#xff0c;本文将编写一个页面&#xff0c;对个股详细数据进行展示。别问涉及到了element-plus中分页的写法&#xff0c;对于这部分知识将会做重点讲解。 首先看一…

计算机网络课程设计-企业网三层架构

&#xff08;单人版&#xff09; 摘 要 本篇报告主要解决了为一家名为西宫的公司网络搭建问题&#xff0c;该网络采用企业网三层架构对完了过进行设计。首先使用以太网中继&#xff0c;主要使用VLAN划分的技术来划定不同部门。使用MSTP对每个组配置生成树&#xff0c;防止交换机…

TecoGAN视频超分辨率算法

1. 摘要 对抗训练在单图像超分辨率任务中非常成功&#xff0c;因为它可以获得逼真、高度细致的输出结果。因此&#xff0c;当前最优的视频超分辨率方法仍然支持较简单的范数&#xff08;如 L2&#xff09;作为对抗损失函数。直接向量范数作损失函数求平均的本质可以轻松带来时…

ubuntu:beyond compare 4 This license key has been revoked 解决办法

https://www.cnblogs.com/zhibei/p/12095431.html 错误如图所示&#xff1a; 解决办法&#xff1a; &#xff08;1&#xff09;先用find命令找到bcompare所在位置&#xff1a;sudo find /home/ -name *bcompare &#xff08;2&#xff09;进入 /home/whf/.config,删除/bco…

【UnityShader入门精要学习笔记】(1)了解渲染流水线

本系列为作者学习UnityShader入门精要而作的笔记&#xff0c;内容将包括&#xff1a; 书本中句子照抄 个人批注项目源码一堆新手会犯的错误潜在的太监断更&#xff0c;有始无终 总之适用于同样开始学习Shader的同学们进行有取舍的参考。 文章目录 渲染流水线什么是流水线什么…

BLP模型

本篇文章是调研了许多资料后对 BLP 模型的一个总结 首发公号&#xff1a;Rand_cs MLS&#xff0c;Multi-level Security&#xff0c;主要关心的是数据机密性 D. Elliott Bell 和 Leonard J. LaPadula 在 1996 年提出了基本的 BLP 模型&#xff0c;主要有两个性质&#xff1a;…

[线代]不挂科猴博士

行列式的性质 行列式的计算及应用 矩阵的运算上(加减,相乘,取行列式) 矩阵的运算下(转置,逆,秩) 向量组与线性空间 解方程组

openGauss学习笔记-182 openGauss 数据库运维-升级-升级前准备与检查

文章目录 openGauss学习笔记-182 openGauss 数据库运维-升级-升级前准备与检查182.1 升级前准备与检查清单182.2 收集节点信息182.3 备份数据182.4 获取升级包182.5 健康检查182.5.1 前提条件182.5.2 操作步骤 182.6 检查数据库节点磁盘使用率182.7 检查数据库状态182.7.1 验证…

exposure_line 是如何曝光的 ?

1、读者提问&#xff1a; exposure_line 是如何曝光的&#xff0c;我看网上说这个代表的是一帧曝光多少行&#xff0c; 那如果一帧 exposure_line 小于frame_length&#xff0c;那一帧后面的行就不曝光吗&#xff1f; 不知道怎么理解&#xff0c;是曝光到1500行&#xff0c;…

动态内存分配函数

malloc void* malloc( unsigned size) 申请size个字节的地址连续的内存单元 成功则返回指向内存块的指针, 失败则返回NULL malloc不对申请的空间初始化 calloc void*calloc&#xff08;unsigned n&#xff0c;unsigmed size&#xff09; 申请n* size字节的个地址连续的内…

骑砍战团MOD开发(30)-游戏大地图map.txt

骑砍1战团mod开发-大地图制作方法_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1rz4y1c7wH/ 一.骑砍游戏大地图 骑砍RTS视角游戏大地图 大地图静态模型(map.txt) 军团/城镇图标(module_parties.py). 骑砍大地图的战争迷雾和天气通过API进行管理和控制: # Weather-h…

数据库视图学习

视图 视图&#xff08;view&#xff09;是一种虚拟存在的表。视图中的数据并不在数据库中实际存在&#xff0c;行和列数据来自定义视图的查询中使用的表&#xff0c;并且是在使用视图时动态生成的。通俗的讲&#xff0c;视图只保存了查询的SQL逻辑&#xff0c;不保存查询结果&…

Zookeeper注册中心实战

Java学习手册面试指南&#xff1a;https://javaxiaobear.cn Spring Cloud Zookeeper通过自动配置和绑定到 Spring 环境和其他 Spring 编程模型习惯用法&#xff0c;为 Spring Boot 应用程序提供Apache Zookeeper集成。通过一些简单的注释&#xff0c;您可以快速启用和配置应用…