堆的相关特点

news2024/11/14 15:08:52

一.建堆的两种方法

给定一个数组,其中数组里面的元素个数是n个如何能够把这个数组建立成为一个堆,今天探讨两种方法,分别是向上调整法和向下调整法,分别探讨他们的时间复杂度

向上调整法(以小堆为例)

回顾一下向上调整法

关于向上调整法,我们之前的具体思路是:比较父节点和子节点的大小,如果子节点比父节点小的话就交换两个的值

//交换两个数的值
void Swap(int* a, int* b)
{
	int temp = *a;
	*a = *b;
	*b = temp;
}
//向上调整算法
void AdjustUp(int* a, int n)
{
	int child = n;
	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;
		}
		
	}
}

那么如何运用上面的算法嘞

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

结果如下

通过画图,我们了解到该结果是正确的

时间复杂度

关于堆(设堆的高度为h)

        

第几层节点数每个节点向上调的次数
02^0 0
12^11
22^22
32^33
h-12^(h-1)h-1

总共调的次数为

O(h)=2^1*1+2^2*2+2^3*3+……+2^(h-1)*(h-1)

两边同时乘以一个2

2O(h)=         2^2*1+2^3*2+2^4*3+……+2^h*(h-1)

上面两个式子相减得到

O(h)=-(2^1+2^2+2^3+……+2^(h-1))+2^h*(h-1)

根据等比数列的前n项和公式得到

O(h)=2^h*(h-2)+2

根据节点数和高度得关系:N=2^h-1 得到:h=log2(N+1)

O(N)=(N+1)[log2(N+1)-2]+2

所以向上调整法建堆的时间复杂度是

O(N)=N*log2(N)

向下调整法(以小堆为例)

思路:从倒数第一个非叶子开始(也就是倒数第二层),一直向下调

void AdjustDown(int* a, int n, int parent)
{
	int child = parent * 2 + 1;
	while (child < n)
	{
		// 假设法,选出左右孩子中小的那个孩子
		if (child + 1 < n && a[child + 1]< a[child])
		{
			++child;
		}

		if (a[child] < a[parent])
		{
			Swap(&a[child], &a[parent]);
			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
			break;
		}
	}
}
int main()
{
	int a[] = { 2,1,4,6,8,3,9};
	int n = sizeof(a) / sizeof(a[0]);
	for (int i = (n - 1 - 1) / 2; i >= 0; i--)
	{
		AdjustDown(a, n, i);
	}
	for (int i = 0; i < n; i++)
	{
		printf("%d ", a[i]);
	}
	return 0;
}

时间复杂度

层数节点调整次数
12^0h-1
22^1h-2
32^2h-3
42^3h-4
h2^(h-1)0

所以:

O(h)=2^0*(h-1)+2^1*(h-2)+2^2*(h-3)+……+2^(h-2)*1

等式两边同时乘以一个2得到

2*O(h)=            2^1*(h-1)+2^2*(h-2)+……+2^(h-2)*2+2^(h-1)*1

两式相减得到

O(h)=1-h+2^1+2^2+……+2^(h-1)+2^0-2^0

化简得到 O(N)=N-log2(N+1)

所以向下调整法的时间复杂度为O(N)

堆排序(以升序为例)

给定一个数组,叫你如何排序嘞,这里我们运用建立堆的方式?

关于是建立大堆还是小堆

如果建立小堆的话,不便于后续的操作,这里我们建立一个大堆的方式

那么,如何通过一个大堆来实现数组的升序排序嘞?

比如下面的大堆,先交换数组首尾的值,交换之后不把最后一个元素看做堆里面的元素,继续向下调整,然后重复上面的步骤

int main()
{
	int a[] = { 46,23,40,35,27,29,30,24 };
	int n = sizeof(a) / sizeof(a[0]);
	for (int i = (n - 1 - 1) / 2; i >= 0; i--)   //时间复杂度O(N)
	{
		AdjustDown(a, n, i);
	}
	int end = n - 1;
	while (end >= 0)                             //时间复杂度O(N*logN)
	{
		Swap(&a[0], &a[end]);
		AdjustDown(a, end, 0);
		end--;
	}
	for (int i = 0; i < n; i++)
	{
		printf("%d ", a[i]);
	}
	return 0;
}                                                       //总的时间复杂度O(N*logN)

堆的TOPK问题

场景:给定你一定量的数据,叫你找出最大的10个或者最小的10个数据,如果你用排序的方法来,当这个数据很大的时候,比如100亿,时间复杂度会很大

那么如何用堆的方法来选出前TOPK的数据

1.先建立一个有K个数据的小堆

2.后续的数据和堆顶的数据相比较,如果数据比堆顶的数据大的话,就代替堆顶的数据,这样留下来的数据就是最大的10个

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);
}

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

	const char* file = "data.txt";
	FILE* fout = fopen(file, "r");
	if (fout == NULL)
	{
		perror("fopen error");
		return;
	}

	int val = 0;
	int* minheap = (int*)malloc(sizeof(int) * k);
	if (minheap == NULL)
	{
		perror("malloc error");
		return;
	}

	for (int i = 0; i < k; i++)
	{
		fscanf(fout, "%d", &minheap[i]);
	}

	// 建k个数据的小堆
	for (int i = (k - 1 - 1) / 2; i >= 0; i--)
	{
		AdjustDown(minheap, k, 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]);
	}

	fclose(fout);

}




int main()
{
	CreateNDate();
	topk();
	
	return 0;
}

运行结果:

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

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

相关文章

【好玩的经典游戏】Docker环境下部署赛车小游戏

【好玩的经典游戏】Docker环境下部署赛车小游戏 一、小游戏介绍1.1 小游戏简介1.2 项目预览二、本次实践介绍2.1 本地环境规划2.2 本次实践介绍三、本地环境检查3.1 安装Docker环境3.2 检查Docker服务状态3.3 检查Docker版本3.4 检查docker compose 版本四、构建容器镜像4.1 下…

解决Visual studio内报错信息:MSB8036:找不到 Windows SDK 版本问题

问题描述&#xff1a; 找不到WindowsSDK版本&#xff0c;请安装所需版本的Windows SDK&#xff0c;或者在项目属性页中通过右键单击解决方案并选择“重定解决方案目标”来更改SDK版本。 首先&#xff0c;如果你尝试了以下两种方法&#xff1a; &#xff08;1&#xff09;重新…

深入理解Java 8的流式API:简化代码,提升效率

文章目录 深入理解Java 8的流式API&#xff1a;简化代码&#xff0c;提升效率一、流 Stream二、Int | Long | Double Stream三、收集器 Collectors 深入理解Java 8的流式API&#xff1a;简化代码&#xff0c;提升效率 Java 8引入了Stream API&#xff0c;它提供了一种新的抽象&…

String 和StringBuilder字符串操作快慢的举例比较

System.currentTimeMillis(); //当前时间与1970年1月1日午夜UTC之间的毫秒差。public class HelloWorld {public static void main(String[] args) {String s1 "";StringBuilder s2 new StringBuilder("");long time System.currentTimeMillis();long s…

Django Web框架~后台美化

1、执行命令 pip install django-simpleui 2、注册simpleui到项目中 3、访问http://127.0.0.1/admin/ 4、设置中文 5、收集admin静态文件 python manage.py collectstatic

Zookeeper入门篇,了解ZK存储特点

Zookeeper入门篇&#xff0c;了解ZK存储特点 前言一、为什么要用 Zookeeper&#xff1f;二、Zookeeper存储特色1. 树状结构2. 节点类型 三、存储位置1. 内存存储1. DataTree2. DataNode 2. 硬盘存储1. 事务日志2. 快照 前言 继上次说完 Zookeeper 的安装后&#xff0c;已经过去…

设计模式学习[2]---策略模式+简单工厂回顾

文章目录 前言1.简单工厂模式回顾2.策略模式3.策略模式简单工厂的结合总结 前言 上一篇讲到简单工厂模式。 在我的理解中工厂的存在就是&#xff0c;为了实例化对象。根据不同条件实例化不同的对象的作用。 这篇博客写的策略模式&#xff0c;可以说是把这个根据不同情况实例化…

pdf2docx - pdf 提取内容转 docx

文章目录 一、关于 pdf2docx主要功能限制 二、安装1、 PyPI2、从remote安装3、从源码安装4、卸载 三、转化 PDF例 1: convert all pages例 2: 转换指定页面例 3: multi-Processing例 4: 转换加密的pdf 四、提取表格五、命令行交互1、按页面范围2、按页码3、Multi-Processing 六…

使用Vue.js集成百度地图WebGL实现3D地图应用

本文由ScriptEcho平台提供技术支持 项目地址&#xff1a;传送门 使用Vue.js集成百度地图WebGL实现3D地图应用 应用场景介绍 本代码用于在Vue.js应用程序中集成百度地图WebGL&#xff0c;实现3D地图的可视化展示。它可以应用于各种场景&#xff0c;例如&#xff1a; 城市规…

助燃新质生产力,魔珐科技亮相IMC2024制造业数字科技大会展示有言AIGC视频工具价值

2024年7月19日&#xff0c;IMC2024第八届制造业数字科技大会在上海盛大开幕&#xff0c;本次大会以《向“智”而行》为主题&#xff0c;250智能制造行业数字化转型企业、行业领军者及实践者共聚一堂&#xff0c;共同助力企业增强技术“硬核力”&#xff0c;为新质生产力蓄势赋能…

【SpringBoot3】全局异常处理

【SpringBoot3】全局异常处理 一、全局异常处理器step1&#xff1a;创建收入数字的页面step2:创建控制器&#xff0c;计算两个整数相除step3:创建自定义异常处理器step5&#xff1a;创建给用提示的页面step6&#xff1a;测试输入&#xff08;10/0&#xff09; 二、BeanValidato…

TCP/IP网络模型详解

在计算机网络领域&#xff0c;网络模型通常指的是 OSI&#xff08;Open Systems Interconnection&#xff09;参考模型或 TCP/IP&#xff08;Transmission Control Protocol/Internet Protocol&#xff09;模型。这些模型描述了网络中数据传输的层次结构&#xff0c;便于理解和…

ROS2从入门到精通2-3:详解机器人3D物理仿真Gazebo与案例分析

目录 0 专栏介绍1 什么是Gazebo?2 Gazebo架构2.1 Gazebo前后端2.2 Gazebo文件格式2.3 Gazebo环境变量3 Gazebo安装与基本界面4 搭建自己的地图4.1 编辑地图4.2 保存地图4.3 加载地图5 常见问题0 专栏介绍 本专栏旨在通过对ROS2的系统学习,掌握ROS2底层基本分布式原理,并具有…

【面试八股文】计算机操作系统

参考&#xff1a;大佬图解文章 → 小林coding 简介&#xff1a;之前在学习小林大佬的八股文时&#xff0c;摘录了一些个人认为比较重要的内容&#xff0c;方便后续自己复习。【持续更新ing ~&#x1f4af;】 注&#xff1a;加五角星标注的&#xff0c;是当前掌握不牢固的&…

WEB攻防-通用漏洞-SQL注入-MYSQL-union一般注入

前置知识 MySQL5.0以后存放一个默认数据库information_schemaschemata表存放该用户创建的所有库名&#xff0c;schemata. schema_name字段存放库名tables表存放该用户创建的所有库名和表明&#xff0c;tables.table_schema字段存放库名&#xff0c;tables.table_name存放表名co…

Elastic 及阿里云 AI 搜索 Tech Day 将于 7 月 27 日在上海举办

活动主题 面向开发者的 AI 搜索相关技术分享&#xff0c;如 RAG、多模态搜索、向量检索等。 活动介绍 参加 Elastic 原厂与阿里云联合举办的 Generative AI 技术交流分享日。借助 The Elastic Search AI Platform&#xff0c; 使用开放且灵活的企业解决方案&#xff0c;以前所…

基于YOLO8的目标检测系统:开启智能视觉识别之旅

文章目录 在线体验快速开始一、项目介绍篇1.1 YOLO81.2 ultralytics1.3 模块介绍1.3.1 scan_task1.3.2 scan_taskflow.py1.3.3 target_dec_app.py 二、核心代码介绍篇2.1 target_dec_app.py2.2 scan_taskflow.py 三、结语 在线体验 基于YOLO8的目标检测系统 基于opencv的摄像头…

Spring Cloud GateWay(4.1.4)

介绍 该项目提供了一个建立在 Spring 生态系统之上的 API 网关&#xff0c;包括&#xff1a;Spring 6、Spring Boot 3 和 Project Reactor。Spring Cloud Gateway 旨在提供一种简单而有效的方法来路由到 API&#xff0c;并为其提供跨领域关注点&#xff0c;例如&#xff1a;安…

华清数据结构day3 24-7-18

基于昨天代码增加增删改查功能 zy.h #ifndef ZY_H #define ZY_H #define MAX 100 //最大容量 //定义学生类型 struct Stu {char name[20];int age;double score; }; //定义班级类型 struct Class {struct Stu student[MAX]; //存放学生的容器int size; //实际…

【Git】(基础篇五)—— Git进阶

Git进阶 之前关于本地和远程仓库的各种操作都已经非常基础了&#xff0c;本文介绍git的一些进阶使用和设置 用户名和邮箱 之前介绍的每一次提交(commit) 都会产生一条日志(log) 信息&#xff0c;这条日志信息不仅会记录提交信息&#xff0c;还会记录执行提交操作的这个用户的…