【数据结构】堆排序和Top-K问题(超详细)

文章目录

  • 堆排序
    • 向上调整建堆
    • 向下调整建堆
    • 堆排序调整过程
  • Top-K问题

堆排序

排升序要建大堆,排降序要建小堆(这里以排升序为例)
排序思想:
1.首先将待排序的n个数建成大堆(此时堆顶是n个数里最大的).
2.将堆顶的值与和最后一个数交换,此时最大的值在n的位置不用管,排序剩下n-1个数(此时根除外左子树和右子树各自依旧是大堆)
3.然后向下调整,选出n-1个数里最大的值,再和n-1个数的最后一个值交换,此时n-1位置放的是第二大的值
4.然后再排剩下的n-2个数,重复就能得到这升序。

以这个数组a[] = { 4,6,2,1,5,8,2,9 }为例
这里建堆有两种方法:

向上调整建堆

1.把数组的第一个数当成一个堆,然后往后插入值再向上调整
在这里插入图片描述
在这里插入图片描述
这种建堆的时间复杂度为O(NlogN)
在这里插入图片描述

向下调整建堆

2.找到最后一个数的位置,然后找到它的父亲,再调整。
在这里插入图片描述
在这里插入图片描述
这种方法的建堆时间复杂度为O(N)
在这里插入图片描述
我们建堆肯定首选时间复杂度低的咯,所以我们一般建堆都是用向下调整建堆。


//这里是排升序,所以要建大堆
//交换函数
void Swap(HDataType* p1, HDataType* p2)
{
	HDataType tmp = *p1;
	*p1 = *p2;
	*p2 = tmp;

}

//向下调整算法
void AdjustDown(HDataType* a, int size, int parent)
{
	//假设左孩子大
	int child = parent * 2 + 1;

	while (child < size)
	{
		if (child + 1 < size && a[child + 1] > a[child])//确保有右孩子,如果错了,更新到右边
		{
			++child;
		}
		if (a[child] > a[parent])
		{
			Swap(&a[child], &a[parent]);

			parent = child;
			child = child * 2 + 1;
		}
		else
		{
			break;
		}
	}

}
//向上调整算法
void AdjustUp(HDataType* a, int child)
{
	int parent = (child - 1) / 2;
	while (child > 0)
	{
		if (a[child] > a[parent])
		{
			Swap(&a[parent], &a[child]);
			child = parent;
			parent = (parent - 1) / 2;
		}
		else
		{
			break;
		}
	}

}
void Heapsort(HDataType* a, int n)
{
	建堆N*logN
	//for (int i = 1; i < n; i++)
	//{
	//	AdjustUp(a, i);
	//}

	//建堆N
	for (int i = (n - 1 - 1) / 2; i >= 0; i--)
	{
		AdjustDown(a, n, i);
	}

	//排序N*logN
	int end = n - 1;
	while (end > 0)
	{
		Swap(&a[0], &a[end]);
		AdjustDown(a, end, 0);
		--end;
	}
}

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

	}
	printf("\n");

	return 0;
}

堆排序调整过程

当在h层时:有2^h-1个元素, 从最顶上到最底下需要走最多h-1次
从最顶上到最底下 ,所有元素需要花费的次数为 2^h-1 * (h-1)

当在h - 1层时:有2^h-2个元素, 从最顶上到最底下需要走最多h-2次
从最顶上到最底下 ,所有元素需要花费的次数为 2^h-2 * (h-2)

最终需要花费的时间就是与上面的向上调整法的结果一样,时间复杂度为O(NlogN)。

堆排序筛选法建堆和堆调整过程结合到一起,时间复杂度是O(N)+O(NlogN),进一步堆排序时间复杂度为O(NlogN)量级。

Top-K问题

TopK问题是一种常见的算法问题,要求从一组元素中找到最大或最小的K个元素。这类问题在日常生活中也经常遇到,例如排名、销量、评分等。TopK问题可以通过排序的方式解决,但是效率较低,一种更高效的方法是利用堆这种数据结构,每次堆顶要么是最大或者最小的元素。这种方法的时间复杂度是N*logK,而且不需要在内存中读入全部的元素,适用于大数据集。

我们举个例:从数据个数为9的数组a[] = { 4,3,7,9,1,5,8,2,8 };中找到前k = 3个最大的数。
第一种方法:刚刚学的堆排序就派上用场了,但是时间复杂度为O(NlogN)
如果数据量非常大,排序就不太可取了(可能数据都不能一下子全部加载到内存中)
第二种方法:就是建N个大小的堆,建N个数的堆为O(N),获取堆顶元素,删除掉堆顶元素为O(logN),上述操作重复 k 次,所以时间复杂度为O(N+klogN)。
如果 N 是 10 亿数,内存中放不下,是放在文件中的,前面两个方法都不能用了。
第三种方法:建k个大小的堆,将剩下的N-k个数与堆顶进行比较,比堆顶大则替换,再进行向下调整,让其再成堆,重复以上动作即可。时间复杂度:O(k + (N-K)logK)。当 N 远大于 K 时,则为O(N
logK)。

结合文件操作演示

//交换函数
void Swap(HDataType* p1, HDataType* p2)
{
	HDataType tmp = *p1;
	*p1 = *p2;
	*p2 = tmp;

}

//向下调整算法
void AdjustDown(HDataType* a, int size, int parent)
{
	//假设左孩子小
	int child = parent * 2 + 1;

	while (child < size)
	{
		if (child + 1 < size && a[child + 1] < a[child])//确保有右孩子,如果错了,更新到右边
		{
			++child;
		}
		if (a[child] < a[parent])
		{
			Swap(&a[child], &a[parent]);

			parent = child;
			child = child * 2 + 1;
		}
		else
		{
			break;
		}
	}

}
//向上调整算法
void AdjustUp(HDataType* a, int child)
{
	int parent = (child - 1) / 2;
	while (child > 0)
	{
		if (a[child] < a[parent])
		{
			Swap(&a[parent], &a[child]);
			child = parent;
			parent = (parent - 1) / 2;
		}
		else
		{
			break;
		}


	}

}
void CreateNData()
{
	int n = 10000000;
	srand(time(0));
	const char* file = "data.txt";
	FILE* fin = fopen(file, "w");
	if (fin == NULL)
	{
		perror("fopen fail");
		return;	
	}
	for (int i = 0; i < n; i++)
	{
		int x = (rand() + i) % 10000000;
		fprintf(fin, "%d\n", x);
	}
	fclose(fin);

}

void PrintTopK(const char* file, int k)
{
	FILE* fout = fopen(file, "r");
	if (fout == NULL)
	{
		perror("fopen fail");
		return;
	}
	//建一个k个数的小堆
	int* minheap = (int*)malloc(sizeof(int) * k);
	if (minheap == NULL)
	{
		perror("malloc fail");
		return;

	}
	//读取前k个,建小堆
	for (int i = 0; i < k; i++)
	{
		fscanf(fout, "%d", &minheap[i]);
		AdjustUp(minheap, i);
	}


	int x = 0;
	while (fscanf(fout, "%d", &x) != EOF)
	{
		if (x > minheap[0])
		{
			minheap[0] = x;
			AdjustDown(minheap, k, 0);
		}
	}
	for (int i = 0; i < k; i++)
	{
		printf("%d ", minheap[i]);
	}
	printf("\n");

	fclose(fout);
}

int main()
{
	CreateNData();
	PrintTopK("data.txt", 5);

	return  0;
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

杨校老师项目之基于SpringBoot+Shiro+Vue的企业人事管理系统

1.获取代码&#xff1a; 有偿获取&#xff1a;mryang511688 2.技术栈 后端 SpringBoot MySQL mybatis-plus shiro Redis 前端 Vue Element-UI 3.开发环境 JDK1.8、Maven3.5.4、MySQL5.7、Redis5.0.5、IntelliJ IDEA、nodejs 4.内置功能 Springboot的项目&#xff0c;…

解锁音频转换:分享5款视频转换mp3的软件(新手必看)

在当今数字化时代&#xff0c;视频转换为MP3音频的需求日益增长&#xff0c;无论是提取音乐、制作音频剪辑&#xff0c;还是享受视频中的声音&#xff0c;都需要一款高效、易用的转换工具。 然而&#xff0c;在众多的选择中&#xff0c;如何找到适合自己的视频转换mp3的软件可…

抓包数据拓展_小迪网络安全笔记

一.Request请求数据包数据格式: 1.请求行:包括请求类型/请求资源路径.协议版本和类型; 例: 2.请求头:一些键值对,浏览器与web服务器之间都可以发送,特定某种含义;yi 3.空行:请求头与请求体之间用空行隔开; 4.请求体:要发送的数据(一般post提交会使用);例如:user123&pass…

⭐️宁波ISO14000认证:⭐️成就“绿色环保”王者之路⭐️

&#x1f308;宁波ISO14000认证&#xff1a;&#x1f498;成就“绿色环保”&#x1f432;王者之路&#x1f34e; &#x1f936;宁波ISO14000认证&#xff1a;&#x1f42f;铸就环保先锋&#xff0c;&#x1f984;引领绿色发展新征程&#x1face; &#x1f682;宁波&#xff0c…

STL <string>--------String的OJ题目

1.题目截图&#xff08;把字符串转换成整数----atoi&#xff09; 1.1题目解析&#xff08;在代码里&#xff09; class Solution { public:int myAtoi(string str) {// 100% 97.45% int len str.size();if(len 0)return 0;int i 0, flag 1, isSignal 0, res 0;while(…

香港人才引进落户条件有哪些?香港优才计划详细介绍!

香港人才引进落户条件有哪些&#xff1f;港府优才计划详细介绍&#xff01; 拿到香港身份&#xff0c;不管是在内地还是在香港亦或是在海外&#xff0c;优势福利都特别多&#xff0c;成为了广大中产的追求。因为香港身份对于子女升学、住房、税收、养老等方面都有很大优势&…

【2024】最新微信小程序商城源码开源版 多用户无限多开+15大功能模块

随着微信小程序市场的蓬勃发展&#xff0c;越来越多的商家和企业意识到了微信小程序作为线上销售平台的重要性。为了满足广大用户的需求&#xff0c;分享一款2024年最新微信小程序商城源码开源版&#xff0c;该版本不仅支持多用户无限多开&#xff0c;还集成了15大功能模块&…

开发调试,远程访问内容、AI项目远程访问,需要的福利

下载地址 Windows 64位 (切勿直接在压缩文件中操作,全部解压到一处后再操作,请关闭某60(会胡乱拦截),可用其他任意安全软件)Mac OS X 64位 (给fastnat执行权限 chmod x ./fastnat_darwin_amd64 终端运行二进制,自行百度,当然建议使用docker方式安装)Linux 64位 (给fastnat执行…

5W 3KVAC隔离 宽电压输入 AC/DC 电源模块——TP05AL系列

TP05AL系列产品是一款经济型开板式开关电源&#xff0c;输出功率为5W&#xff0c;具有可靠性高、小体积、性价比高等特点&#xff0c;广泛用于工控和电力仪器、仪表、智能家居等相关行业。

微服务(Spring Clould)--Nacos的安装、配置

简介&#xff1a;&#xff08;取自官网&#xff09; Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service的首字母简称&#xff0c;一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。 Nacos 致力于帮助您发现、配置和管理微服务。Nacos 提供了…

【CTF Web】NSSCTF 3863 [LitCTF 2023]导弹迷踪 Writeup(JS分析+源码泄漏+信息收集)

[LitCTF 2023]导弹迷踪 你是一颗导弹&#xff0c;你需要&#xff0c;飞到最后&#xff01;&#xff08;通过6道关卡就能拿到flag哦~ Flag形式 NSSCTF{} 出题人 探姬 解法 查看网页源代码。 flag 应该在这些文件里面。 <!-- Game files --><script type"applicat…

Process Monitor下载安装使用教程(图文教程)超详细

「作者简介」&#xff1a;2022年北京冬奥会网络安全中国代表队&#xff0c;CSDN Top100&#xff0c;就职奇安信多年&#xff0c;以实战工作为基础对安全知识体系进行总结与归纳&#xff0c;著作适用于快速入门的 《网络安全自学教程》&#xff0c;内容涵盖系统安全、信息收集等…

6大部分,20 个机器学习算法全面汇总!!建议收藏!(下篇)

上篇地址&#xff1a;6大部分&#xff0c;20 个机器学习算法全面汇总&#xff01;&#xff01;建议收藏&#xff01;&#xff08;上篇&#xff09;-CSDN博客 上篇介绍了 接下来介绍新的内容 半监督学习算法 半监督学习算法结合了监督学习和无监督学习的元素&#xff0c;利用既…

[C++核心编程-08]----C++类和对象之运算符重载

&#x1f3a9; 欢迎来到技术探索的奇幻世界&#x1f468;‍&#x1f4bb; &#x1f4dc; 个人主页&#xff1a;一伦明悦-CSDN博客 ✍&#x1f3fb; 作者简介&#xff1a; C软件开发、Python机器学习爱好者 &#x1f5e3;️ 互动与支持&#xff1a;&#x1f4ac;评论 &…

AVDemo漏洞平台黑盒测试

信息收集 说明一下&#xff1a; 因为是本地的环境&#xff0c;端口这些就不扫描了&#xff0c; 还有这个是某个dalao写的平台&#xff0c;也就检测不到什么cms了&#xff0c; 信息收集&#xff0c;端口&#xff0c;cms这些是必做的&#xff0c; 首先&#xff0c;这里先简单的…

致命错误: 用户 “system“ Password 认证失败 (kbjdbc: autodetected server-_enco

问题在于用户权限不足&#xff0c;修改kingbase安装目录data目录下的的文件sys_hba.conf&#xff0c;修改IPV4部分本地验证方式为trust即可 修改后&#xff0c;打开资源管理器&#xff0c;通过服务找到人大金仓服务&#xff0c;重新启动即可

有趣的css - 文字隐身术效果

大家好&#xff0c;我是 Just&#xff0c;这里是「设计师工作日常」&#xff0c;今天分享的是利用动画属性来模拟文字隐身消失的效果。 《有趣的css》系列最新实例通过公众号「设计师工作日常」发布。 目录 整体效果核心代码html 代码css 部分代码 完整代码如下html 页面css 样…

ip显示地址和实际地址不一样:原因解析与应对策略

在数字化时代&#xff0c;IP地址作为我们在互联网上的身份标识&#xff0c;其重要性不言而喻。然而&#xff0c;有时我们会遇到ip显示地址和实际地址不一样的情况&#xff0c;这不仅可能影响到我们的网络体验&#xff0c;还可能引发一系列安全和隐私问题。那么&#xff0c;造成…

嵌入式学习72-复习(字符设备驱动框架)

编辑 drivers/char/Kconfig 为了在make menuconfig是能够显示出我们写的驱动程序 make menuconfig 编辑 drivers/char/Makefile 才是真正把编写好的源文件加入到编译中去 make modules cp drivers/char/first_driver.ko ~/nfs/rootfs/

26版SPSS操作教程(高级教程第二十三章)

目录 前言 粉丝及官方意见说明 第二十三章一些学习笔记 第二十三章一些操作方法 时间序列模型 时间序列的建立和平稳化 数据假设 具体操作 定义时间变量 时间序列的平稳化 绘制相应的时间序列图 序列图 自相关图&#xff08;autocorrelation chart&#xff09; 对…