堆的概念,性质及其实现

news2024/9/25 2:24:57

1.堆的概念及结构

如果有一个关键码的集合K = { , , ,…, },把它的所有元素按完全二叉树的顺序存储方式存储在一个一维数组中,并满足: <= 且 <= ( >= 且 >= ) i = 0,1,2…,则称为小堆(或大堆)。将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆。
堆的性质:

  • 堆中某个节点的值总是不大于或不小于其父节点的值;
  • 堆总是一棵完全二叉树。
    在这里插入图片描述
1.下列关键字序列为堆的是:()
A 100,60,70,50,32,65
B 60,70,65,50,32,100
C 65,100,70,32,50,60
D 70,65,100,32,50,60
E 32,50,100,70,65,60
F 50,100,70,65,60,32
2.已知小根堆为8,15,10,21,34,16,12,删除关键字 8 之后需重建堆,在此过程中,关键字之间的比较次
数是()。
A 1
B 2
C 3
D 4
3.一组记录排序码为(5 11 7 2 3 17),则利用堆排序方法建立的初始堆为
A(11 5 7 2 3 17)
B(11 5 7 2 17 3)
C(17 11 7 2 3 5)
D(17 11 7 5 3 2)
E(17 7 11 3 5 2)
F(17 7 11 3 2 5)
4.最小堆[0,3,2,5,7,4,6,8],在删除堆顶元素0之后,其结果是()
A[3,2,5,7,4,6,8]
B[2,3,5,7,4,6,8]
C[2,3,4,5,7,8,6]
D[2,3,4,5,6,7,8]

选择题答案
1.A
2.C
3.C
4.C

2.堆的实现

2.1堆的向下调整算法

如果想pop堆顶的数据该怎么办呢?
是不是第一想法就是:嗯,这个简单,直接pop掉堆顶的数据就好了,但是,我们并没有考虑到,当直接pop掉堆顶的数据后,重新调整会破坏堆的结构,很麻烦

所以说,这个方法并不是最优解,这里直接告诉方法:将堆顶的数据和最后一个叶子节点的数据交换,然后将其pop掉,再从被换到堆顶的数据向上调整

现在我们给出一个数组,逻辑上看做一颗完全二叉树。我们通过从根节点开始的向下调整算法可以把它调整成一个小堆。向下调整算法有一个前提:左右子树必须是一个堆,才能调整。
int array[] = {27,15,19,18,28,34,65,49,25,37};
在这里插入图片描述
以27为根的左右子树,都满足小堆的性质,只有根节点不满足,因此只需要将根节点往下调整到合适的位置即可形成堆
在这里插入图片描述
代码实现如下:

//用于pop堆顶,将堆顶的数据与堆尾交换,然后pop堆尾,再调整堆
void AdjustDown(HPDataType* a, int n, int parent)
{
	assert(a);
	int child = 2 * parent + 1;
	while (child<n)
	{
		if (a[child] < a[child + 1])
		{
			child++;
		}

		if (a[child] < a[parent])
		{
			Swap(&a[child], &a[parent]);
			parent = child;
			child = 2 * parent + 1;
		}
		else
		{
			break;
		}
	}
}

使用堆的向下调整算法,最坏的情况下(即一直需要交换结点),需要循环的次数为:h - 1次(h为树的高度)。而 h = l o g 2 ( N + 1 ) h = log_2(N+1) h=log2(N+1)(N为树的总结点数)。所以堆的向下调整算法的时间复杂度为:O(logN) 。

这里引出一个问题,使用堆的向下调整算法需要满足其根结点的左右子树均为大堆或是小堆才行,那么如何才能将一个任意树调整为堆?

2.2 堆的创建

下面我们给出一个数组,这个数组逻辑上可以看做一颗完全二叉树,但是还不是一个堆,现在我们通过算
法,把它构建成一个堆。根节点左右子树不是堆,我们怎么调整呢?这里我们从倒数的第一个非叶子节点的
子树开始调整,一直调整到根节点的树,就可以调整成堆。
int a[] = {1,5,3,8,7,6};
在这里插入图片描述
从最后一个非叶子节点开始(看作一个根),从后往前,按下标,依次作为根去向下调整即可

void HeapCreate(HP* php, HPDataType* a, int n)
{
	assert(php);
	php->a = (HPDataType*)malloc(php->a, sizeof(HPDataType) * n);
	if (php->a == NULL)
	{
		perror("realloc fail");
		exit(-1);
	}
	memcpy(php->a, a, sizeof(HPDataType) * n);
	php->size = php->capacity = n;

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

2.3建堆时间复杂度

因为堆是完全二叉树,而满二叉树也是完全二叉树,此处为了简化使用满二叉树来证明(时间复杂度本来看的就是近似值,多几个节点不影响最终结果):
在这里插入图片描述
在这里插入图片描述

总结:
 堆的向下调整算法的时间复杂度: T ( n ) = O ( l o g ⁡ N ) T ( n ) = O ( log ⁡ N ) T(n)=O(logN)
 建堆的时间复杂度: T ( n ) = O ( N ) T ( n ) = O ( N ) T(n)=O(N)

2.4堆向上调整算法

当我们在一个堆的末尾插入一个数据后,需要对堆进行调整,使其仍然是一个堆,这时需要用到堆的向上调整算法。

向上调整算法的基本思想(以建小堆为例):
 1.将目标结点与其父结点比较。
 2.若目标结点的值比其父结点的值小,则交换目标结点与其父结点的位置,并将原目标结点的父结点当作新的目标结点继续进行向上调整。若目标结点的值比其父结点的值大,则停止向上调整,此时该树已经是小堆了。
代码实现如下:

void Swap(HPDataType* p1, HPDataType* p2)
{
	HPDataType tmp = *p1;
	*p1 = *p2;
	*p2 = tmp;
}
//插入小堆的数向上调整
void AdjustUp(HPDataType* a, int child)
{
	int parent = (child - 1) / 2;
	//while (parent >= 0)  不好
	while (child > 0)
	{
		if (a[child] < a[parent])
		{
			Swap(&a[child], &a[parent]);
			child = parent;
			parent = (child - 1) / 2;
		}
		else
		{
			break;
		}
	}
}

2.5堆的代码实现

堆的初始化

typedef int HPDataType;
typedef struct Heap
{
   HPDataType* a;
   int size;
   int capacity;
}HP;

void HeapInit(HP* php)
{
   assert(php);
   php->a = NULL;
   php->size = php->capacity = 0;
}

堆的销毁

void HeapDestroy(HP* php)
{
   assert(php);
   free(php->a);
   php->a = NULL;
   php->size = php->capacity = 0;
}

堆的打印(物理结构)

void HeapPrint(HP* php)
{
   assert(php);
   for (int i = 0; i < php->size; ++i)
   {
   	printf("%d ", php->a[i]);
   }
   printf("\n");
}

堆的数据插入

void HeapPush(HP* php, HPDataType x)
{
   assert(php);

   // 扩容
   if (php->size == php->capacity)
   {
   	int newCapacity = php->capacity == 0 ? 4 : php->capacity * 2;
   	HPDataType* tmp = (HPDataType*)realloc(php->a, sizeof(HPDataType) * newCapacity);
   	if (tmp == NULL)
   	{
   		perror("realloc fail");
   		exit(-1);
   	}

   	php->a = tmp;
   	php->capacity = newCapacity;
   }

   php->a[php->size] = x;
   php->size++;

   AdjustUp(php->a, php->size - 1);
}

堆的数据删除

void HeapPop(HP* php)
{
   assert(php);
   assert(php->size > 0);

   Swap(&php->a[0], &php->a[php->size - 1]);
   php->size--;

   AdjustDown(php->a, php->size, 0);
}

堆顶数据获取

HPDataType HeapTop(HP* php)
{
   assert(php);

   return php->a[0];
}

堆的判空

bool HeapEmpty(HP* php)
{
   assert(php);

   return php->size == 0;
}

获取堆的数据个数

int HeapSize(HP* php)
{
   assert(php);

   return php->size;
}

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

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

相关文章

系统移植,GNU命令,Uboot移植

一.GNU命令 1、addr2line 把程序地址转换为文件名和行号 做调试 2、ar 建立&#xff0c;修改&#xff0c;提取归档文件 3、Id:GNU arm-none-linux-gnueabi-ld start.o main.o -Tmap.lds -o uart.elf 链接器 4、as 主要用来编译GNU编译器gcc输出的汇编文件&a…

JVM实战(31)——内存溢出之请求超时

一、简介 本章&#xff0c;我们将通过实际案例讲解一个Web应用的内存溢出问题&#xff0c;该内存溢出问题的排查涉及Tomcat的一些底层原理&#xff0c;最终排查发现是由于请求超时问题导致&#xff0c;我们先来看下系统的背景。 1.1 系统背景 生产环境的一个系统发生告警&…

PyTorch内置损失函数汇总 !!

文章目录 一、损失函数的概念 二、Pytorch内置损失函数 1. nn.CrossEntropyLoss 2. nn.NLLLoss 3. nn.NLLLoss2d 4. nn.BCELoss 5. nn.BCEWithLogitsLoss 6. nn.L1Loss 7. nn.MSELoss 8. nn.SmoothL1Loss 9. nn.PoissonNLLLoss 10. nn.KLDivLoss 11. nn.MarginRankingLoss 12. …

sylar高性能服务器-日志(P26-P29)内容记录

文章目录 P26&#xff1a;协程01一、方法函数二、结果展示 P27-28&#xff1a;协程02-03一、方法函数二、结果展示 P29&#xff1a;协程04一、方法函数二、结果展示 P26&#xff1a;协程01 ​ 本节内容主要介绍了开始协程的一些准备工作&#xff0c;平常我们使用assert断言时&…

香港web3盛会:Unisat确认参加Big Demo Day项目路演

本次“Big Demo Day”将于1月31日举办第十期&#xff0c;是由Zeepr 总冠名&#xff0c;Central Research、Techub News联合主办、数码港、852web3支持举行的大型线下活动。Big Demo Day集结了Web2和Web3行业精英聚焦香港市场。 Unisat确认参加 Big Demo Day 线下活动&#xff0…

HIS项目介绍、项目环境准备、版本控制介绍、Git基础、Git指针、Git分支、Git标签

案例1&#xff1a;项目环境准备 环境准备说明&#xff1a; 本阶段共使用虚拟机6台&#xff0c;操作系统使用RockyLinux8.6 环境准备要求&#xff1a; 最小化安装即可配置好主机名和IP地址搭建好yum源关闭防火墙和SELinux!!! 项目主机列表 主机名IP地址规格角色服务Progra…

python内置函数有哪些?整理到了7大分类48个函数,都是工作中常用的函数

python内置函数 一、入门函数 1.input() 功能&#xff1a; 接受标准输入&#xff0c;返回字符串类型 语法格式&#xff1a; input([提示信息])实例&#xff1a; # input 函数介绍text input("请输入信息:") print("收到的数据是:%s" % (text))#输出…

“趣味夕阳,乐享生活”小组活动(第二节)

立冬以来&#xff0c;天气日渐寒冷&#xff0c;气温变化较大&#xff0c;各种传染病多发&#xff0c;为进一步增强老年人冬季预防传染病保健意识及科学合理健康的生活方式。近日&#xff0c;1月22日&#xff0c;南阳市人人社工灌涨站开展了“趣味夕阳&#xff0c;乐享生活”小组…

在IntelliJ IDEA中通过Spring Boot集成达梦数据库:从入门到精通

目录 博客前言 一.创建springboot项目 新建项目 选择创建类型​编辑 测试 二.集成达梦数据库 添加达梦数据库部分依赖 添加数据库驱动包 配置数据库连接信息 编写测试代码 验证连接是否成功 博客前言 随着数字化时代的到来&#xff0c;数据库在应用程序中的地位越来…

RS450服务器硬盘亮黄灯故障及从MegaRAID9240-4i阵列卡的恢复业务过程

最近一台ThinkCenter RS450服务器硬盘亮黄灯&#xff0c;引起进入系统很慢&#xff0c;于是将业务系统备份后&#xff0c;对该服务器硬盘进行修复。 该服务器的总共三块硬盘组件了Raid5&#xff0c;因此待第一块盘亮红灯后&#xff0c;尝试进入Raid管理器&#xff0c;将报错的…

gitlab备份-迁移-升级方案9.2.7升级到15版本最佳实践

背景 了解官方提供的版本的升级方案 - GitLab 8: 8.11.Z 8.12.0 8.17.7 - GitLab 9: 9.0.13 9.5.10 9.2.7 - GitLab 10: 10.0.7 10.8.7 - GitLab 11: 11.0.6 11.11.8 - GitLab 12: 12.0.12 12.1.17 12.10.14 - GitLab 13: 13.0.14 13.1.11 13.8.8 13.12.15 - G…

HTML小白入门学习-列表标签

前言 在上一篇文章中&#xff0c;我们学习了下图所示的几个文本格式标签&#xff0c;分别是加粗、斜体、下划线、删除线、下标和上标&#xff0c;忘记了的小伙伴可以回去再看看哦。 在网页中&#xff0c;我们也会经常看到列表&#xff0c;比如某资讯网页的信息列表&#xff…

C# Bitmap类学习1

Bitmap对象封装了GDI中的一个位图&#xff0c;此位图由图形图像及其属性的像素数据组成.因此Bitmap是用于处理由像素数据定义的图像的对象。 using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using …

【新加坡机器人学会支持】第三届工程管理与信息科学国际学术会议 (EMIS 2024)

第三届工程管理与信息科学国际学术会议 (EMIS 2024) 2024 3rd International Conference on Engineering Management and Information Science 【国际高级别专家出席/新加坡机器人学会支持】 第三届工程管理与信息科学国际学术会议 (EMIS 2024)将于2024年4月12-14日在中国洛…

SpringBoot项目多数据源配置与MyBatis拦截器生效问题解析

在日常项目开发中&#xff0c;由于某些原因&#xff0c;一个服务的数据源可能来自不同的库&#xff0c;比如&#xff1a; 对接提供的中间库&#xff0c;需要查询需要的数据同步数据&#xff0c;需要将一个库的数据同步到另一个库&#xff0c;做为同步工具的服务对接第三方系统…

黑马Java——面向对象进阶(static继承)

1.static静态变量 静态变量是随着类的加载而加载的&#xff0c;优先与对象出现的

“豚门”、“吗喽”,为啥品牌宣传瞄上网红动物?

近期&#xff0c;新茶饮品牌喜茶联名红山动物园&#xff0c;凭借可爱周边拿捏无数消费者&#xff0c;再往前一段时间&#xff0c;还有奈雪联名“吗喽”表情包&#xff0c;为什么品牌宣传会瞄上网红动物&#xff0c;今天媒介盒子就来和大家聊聊。 一、 萌元素引起用户情绪共鸣 …

C#使用DateTime.Now.AddDays方法获取任一天的信息

目录 一、使用DateTime对象的AddDays方法获取任一天信息方法 二、举例说明获取昨天的信息 三、涉及到的知识点 1. MessageBox.Show(&#xff09;中信息分行的办法 使用DateTime.Now属性可以得到当前的日期信息&#xff0c;此时调用ToString方法&#xff0c;并在该方法中添加…

使用PHP自定义一个加密算法,实现编码配合加密,将自己姓名的明文加密一下

<meta charset"UTF-8"> <?phpfunction customEncrypt($lin, $key mySecretKey){// 定义一个简单的替换规则$li array(L > M, I > Y, Y > O, A > N, E > Q, );$yan ;for($i 0; $i < strlen($lin); $i){$char $lin[$i];if(isset($li[…

27.移除元素(力扣LeetCode)

文章目录 27.移除元素&#xff08;力扣LeetCode&#xff09;题目描述方法一&#xff1a;vector成员函数&#xff1a;erase方法二&#xff1a;暴力解法方法三&#xff1a;双指针法 27.移除元素&#xff08;力扣LeetCode&#xff09; 题目描述 给你一个数组 nums 和一个值 val&…