第八章:堆的讲解与实现

news2024/11/16 22:35:00

第八章:堆的实现与堆相关的算法

  • 一、堆
    • 1、什么是堆?
    • 2、堆的实现
      • (1)堆的定义
      • (2)接口函数
        • 初始化
        • 销毁
        • 插入
        • 删除
        • 判断是否为空
        • 返回堆顶
        • 返回堆中的元素个数
        • 打印

一、堆

1、什么是堆?

在前面的章节中,我们了解到了树、二叉树等相关的概念,那么今天所讲解的堆就是基于二叉树中的完全二叉树实现的。那么在完全二叉树的基础上,堆还满足该性质:堆中的子节点始终小于等于(大于等于)父节点。

倘若,堆的父节点始终小于等于其子节点,我们就称之为小根堆
倘若,堆的父节点始终大于等于其子节点,我们就称之为大根堆

堆的逻辑结构及物理结构;

在这里插入图片描述

从上述的物理结构我们可以知道,我们接下来的代码实现是基于数组的。因此,我们将采用动态顺序表的思路来存储堆。

2、堆的实现

(1)堆的定义

typedef int ElementType;
typedef struct Heap
{
	ElementType* a;
	int size;
	int capacity;
}Heap;

(2)接口函数

初始化

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

销毁

void HeapDestory(Heap* h)
{
	assert(h);
	free(h->a);
	h->a = NULL;
	h->size = h->capacity = 0;
}

插入

因为我们是在数组中实现堆的,但是数组在中部插入的时间复杂度是O(N),头部插入的时间复杂度也是O(N)。因此,我们是在最后一个位置插入一个数据,然后再让这个数据向上移动。但是我们新插入的节点如何向前移动?

在下面的小根堆中,我们假设在尾部插入一个1。
在这里插入图片描述
从图中我们能够看出,我们将一个数据向上进行调整的时候,我们只需要关注该节点所在的路径。我们不妨把这条线抽离出来:
在这里插入图片描述
此时,我们发现,1需要向上移动的话,只需要和1的祖宗们相比较。因此,我们可以写出AdjustUp的函数。

void AdjustUp(Heap* h, int child)
{
	assert(h);
	while (child>0)
	{
		int parent = (child - 1) >> 1;
		if (h->a[child] < h->a[parent])
		{
			ElementType tmp = h->a[child];
			h->a[child] = h->a[parent];
			h->a[parent] = tmp;
			child = parent;
		}
		else
		{
			break;
		}
	}
}

void HeapPush(Heap* h,ElementType x)
{
	assert(h);
	if (h->size == h->capacity)
	{
		size_t newcapacity = (h->capacity == 0) ? 4 : 2 * h->capacity;
		ElementType* tmp = realloc(h->a,sizeof(ElementType)*newcapacity);
		if (tmp == NULL)
		{
			printf("realloc fail\n");
			exit(-1);
		}
		h->a = tmp;
		h->capacity = newcapacity;
	}
	h->a[h->size] = x;
	h->size++;
	AdjustUp(h,h->size-1);
}

当我们调整好后,就会出现下面的样子:
在这里插入图片描述

删除

在插入函数的铺垫下,这里讲解删除就好理解多了。我们的堆删除的元素一般是堆顶元素。因此,我们这里需要删除的是堆顶。但数组中删除堆顶元素的时间复杂度是O(N)。这是相当复杂的,而尾删的时间复杂度是O(1),于是我们这里也是先将尾部元素和堆顶元素进行交换,然后再将堆顶元素向下移动。
在这里插入图片描述
但是我们这里要解释一下:为什么要和子结点中较小的交换。
在这里插入图片描述
通过上述反例,我们就发现了根节点和较小子节点交换的重要性。

void AdjustDown(Heap* h, int parent)
{
	assert(h);
	int child = parent * 2 + 1;
	while (child<h->size)
	{
		if (child + 1 < h->size && h->a[child + 1] < h->a[child])
		{
			child++;
		}
		if (h->a[child] < h->a[parent])
		{
			ElementType tmp = h->a[child];
			h->a[child] = h->a[parent];
			h->a[parent] = tmp;
			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
			break;
		}
	}
}

void HeapPop(Heap* h)
{
	assert(h);
	assert(!HeapEmpty(h));
	ElementType tmp = h->a[0];
	h->a[0] = h->a[h->size - 1];
	h->a[h->size - 1] = tmp;
	h->size--;
	AdjustDown(h,0);
}

判断是否为空

bool HeapEmpty(Heap* h)
{
	assert(h);
	return h->size == 0;
}

因为我们在C语言中本身是没有bool的,所以我们需要包含头文件<stdbool.h>

返回堆顶

这里要注意一下,返回之前我们要判断堆是否为空。

ElementType HeapTop(Heap* h)
{
	assert(h);
	assert(!HeapEmpty(h));
	return h->a[0];
}

返回堆中的元素个数

int HeapSize(Heap* h)
{
	assert(h);
	return h->size;
}

打印

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

这里我们需要注意是,打印出来的是一个数组,因此,我们要根据完全二叉树的下标之间的规律去还原堆的逻辑结构。

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

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

相关文章

机器学习算法交叉验证最频繁犯的6个错误

交叉验证是保证模型有效的方法&#xff0c;同时也是防止模型过拟合的方法。但在有限的数据集中&#xff0c;交叉验证容易出现一些错误使用。 本文将介绍在使用交叉验证中&#xff0c;常见的一些错误情况&#xff0c;希望读者在阅读后可以避免再次犯错。 文章目录技术提升什么是…

轻松玩转树莓派Pico之四、Ubuntu下在线debug环境搭建

目录 1、openocd编译安装 1&#xff09;安装依赖 2&#xff09;下载 3&#xff09;编译 4&#xff09;安装GDB 2、Picoprobe编译与连接 1&#xff09;下载、编译 2&#xff09;开发板连接 3&#xff09;Picoprobe连接至Linux 3、手工运行openocd和gdb 4、VSCode在线调…

Niantic CEO:AR有望取代二维码,理想的AR眼镜还需3-5年

早前&#xff0c;Niantic CEO John Hanke就曾谈到过对于元宇宙的愿景&#xff0c;相比于VR的沉浸式体验&#xff0c;他认为未来元宇宙应该是将虚拟和现实融合的AR体验。尽管如此&#xff0c;现在还没有一款足够普及的AR眼镜产品&#xff0c;仅依赖手机、平板电脑并不能展现沉浸…

《Linux-常见指令详解》

目录 Linux背景 开源 操作系统的理解 问题 1.空文件占磁盘空间吗&#xff1f; 2.创建的文件是在内存中还是磁盘中&#xff1f; 3.绝对路径和相对路径的区别 4.Linux下的文件后缀可以随便写&#xff0c;不同于Windows 常见指令和权限 查看 Linux 主机 ip 使用 XSh…

Alibaba 官方上线,SpringBoot+SpringCloud 全彩指南(第五版)

Alibaba 作为国内一线互联网大厂&#xff0c;其中 springcloudAlibaba 更是阿里微服务最具代表性的技术之一&#xff0c;很多人只知道 springcloudAlibaba 其实面向微服务技术基本上都有的下面就给大家推荐一份 Alibaba 官网最新版&#xff1a;SpringBootSpringCloud 微服务全栈…

面试系列分布式事务:谈谈2PC的理解

2PC其实就是两阶段提交的分布式事务中事务类型&#xff0c;两阶段提交就是分两个阶段提交&#xff1a; 第一阶段询问各个事务数据源是否准备好。 第二阶段才真正将数据提交给事务数据源。 为了保证该事务可以满足ACID&#xff0c;就引入一个协调者&#xff08;Cooradinator&…

【OpenCV-Python】教程:3-9 轮廓(2)轮廓特征

OpenCV Python 轮廓特征 【目标】 轮廓矩轮廓周长、轮廓面积轮廓拟合、轮廓凸包、轮廓凹凸性检查外接矩形、最小包围圈椭圆拟合、直线拟合 【代码】 周长、面积、矩 第一幅图像为原始轮廓图像&#xff0c;第二幅图像为轮廓点拟合图像&#xff08;精度为周长的1/10&#xff…

Docker——Windows版本Docker安装

目录 一、简介 1.1 Docker如何解决大型项目依赖关系复杂&#xff0c;不同组件依赖的兼容性问题&#xff1f; 1.2 Docker如何解决开发、测试、生产环境有差异的问题 1.3 Docker 和 虚拟机的区别 1.4 Docker架构 1.5 总结 二、Docker安装&#xff08;Windows版&#xff09; 2.1…

电容笔可以用什么代替?好用电容笔品牌推荐

在互联网办公、互联网教学等领域&#xff0c;电容笔再次成为全球流行的电子产品。用平替电容笔来代替苹果的电容笔吗&#xff1f;实际上&#xff0c;我们可以考虑买一支平替电容笔&#xff0c;而不用再买昂贵的苹果 Pencil。一支平替电容笔&#xff0c;一两百块钱&#xff0c;比…

spring web 简单项目数据库查询 纯注解版替代web.xml

关键词句&#xff1a;第一个spring 简单项目 纯注解 包括替代web.xml 文件 第一个spring mvc web 简单项目 纯注解 用纯注解写spring web 简单项目 纯注解写web 项目 spring 写数据库 查询 注解方式 spring 数据接链接池 用的阿里的 spring jdbc jdbcTemplate类使用…

python--星际大战(基础版)

实现功能&#xff1a; 运用python的pygame模块实现上方出现一群体的敌机&#xff0c;每个敌机会随机不定时发射子弹&#xff0c;下方是玩家飞机&#xff0c;通过控制方向和发射子弹来摧毁所以敌机&#xff0c;在游戏开始前会有一个计时器&#xff08;3秒&#xff09;计时结束&…

3、Pinpoint-Agent端注册服务到Server端

0、此节简介 此章节大部分操作是在另一台服务器上&#xff0c;vm7。 Agent端配置 项目发布 注册到Pinpoint服务端 接口调用&#xff0c;服务端查看详情 1、Agent端配置 Agent推荐使用和Pinpoint服务端同样的版本。 1.1、下载Pinpoint-Java-Agent包 Github下载链接&#xff1a;h…

第七章 规范化:Eslint + Prettier + Husky

第七章 规范化&#xff1a;Eslint Prettier Husky 为了项目能够长期健康的发展。代码的规范性建设非常重要。只有纪律严明的队伍才能不断打胜仗。 规范制定容易&#xff0c;执行的难度很大。 项目规范可以分为&#xff1a; 编码规范&#xff1b;项目结构规范&#xff1b;…

hyper-v虚拟机ubuntu ssh配置

环境描述&#xff1a; 本地机&#xff1a;win10系统 linux机&#xff1a;hyper-v 虚拟机中的ubuntu 1、ssh 安装和启用 //安装ssh sudo apt-get install ssh//启用ssh service ssh start//查看ssh状态 service ssh status 2、网络工具安装和ip查看 //安装网络工具 sudo ap…

[附源码]SSM计算机毕业设计基于篮球云网站JAVA

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

$.ajax异步请求总结

$.ajax()简单介绍 AJAX 是一种与服务器交换数据的技术&#xff0c;可以在不重新载入整个页面的情况下更新网页的一部分 $.ajax()是万能的&#xff0c;是最基础&#xff0c;最全面的那个&#xff1b;剩余的方法都是针对某种特定场景下的$.ajax()的简化形式 $.ajax()、$.post()…

Java环境变量学习

0. 找到你的安装路径 C:\Program Files\Java 这种语言的开发工具&#xff0c;重要的东西建议就安装在C盘 0.1 里面有什么&#xff1f; 其实就是很多java命令而已 用来编译的&#xff0c;运行的 JDK开发用的JRE运行用的 就像python中给你开发工具的同时&#xff0c;再给你一个…

[附源码]java毕业设计学习资源共享与在线学习系统

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

Jetpack Compose中的state核心思想

Compose 中的状态 应用的“状态”是指可以随时间变化的任何值。这是一个非常宽泛的定义&#xff0c;从 Room 数据库到类的变量&#xff0c;全部涵盖在内。 所有 Android 应用都会向用户显示状态。下面是 Android 应用中的一些状态示例&#xff1a; 聊天应用中最新收到的消息…

Unity3D : 本地坐标系,世界坐标系,和TransformPoint,TransformVector,TransformDirection的区别

目录 一、世界坐标系与本地坐标系 二、srcGameObject.transform.TransformPoint(Vector3 vec) 三、srcGameObject.transform.TransformVector(Vector3 vec) 四、srcGameObject.transform.TransformDirection(Vector3 vec) 五:示例 一、世界坐标系与本地坐标系 世界坐标很…