100.【C语言】数据结构之二叉树的堆实现 上

目录

1.顺序结构

2.示意图

 ​编辑

从物理结构还原为逻辑结构的方法

3.父子节点编号的规律

4.顺序存储的前提条件

5.堆的简介

堆的定义

堆的两个重要性质

小根堆和大根堆 

6.堆的插入

7.堆的实现及操作堆的函数

堆的结构体定义

堆初始化函数HeapInit

堆插入元素函数HeapPush

堆向上调整函数AdjustUp

写法1

写法2

写法3

提问

测试堆插入函数


1.顺序结构

存储二叉树的两种结构:一种顺序结构,一种链式结构本文讲顺序结构


2.示意图

 

上方图中的数字0~6代表各个节点的编号 

逻辑结构:方便人理解的结构 物理结构:实实在在存储的结构

可见顺序结构的底层是用数组(连续)存储的

从物理结构还原为逻辑结构的方法

对于满二叉树而言,

第一层有一个节点,第二层有两个节点,第一层有四个节点......

则可按层拆分

再组合

加上线

 对于完全二叉树而言,做法和上述类似,不再赘述

3.父子节点编号的规律

比如求F的父节点,如果画图则太慢,其实可以看出规律

F编号为5,其父节点C编号为2;E编号为4,其父节点B编号为1;

发现[\frac{5-1}{2}]=2,[\frac{4-1}{2}]=[1.5]=1(注:[x]为高斯函数,又称向下取整函数)

★★★求父节点b编号的公式:[\frac{child-1}{2}]=father

在C语言中为father = (child-1)/2;father获得表达式的商

如果给出父节点的编号,求左孩子和右孩子的编号

父节点C编号为2,则左孩子F的编号为2*2+1,则右孩子G的编号为2*2+2

★★★求孩子节点编号的公式:左孩子:2*father+1  右孩子:2*father+2

4.顺序存储的前提条件

结论:完全二叉树(含满二叉树)适合用顺序存储

如果非完全二叉树,存储会浪费空间

5.堆的简介

堆的定义

如果有一个关键码的集合K = {k_0,k_1, k_2,…,k_{n-1}},把它的所有元素按完全二叉树的顺序存储方式存储在一个一维数组中,并满足:K_i <= K_{2*i+1} 且 K_i<= K_{2*i+2} (K_i >= K_{2*i+1} 且 K_i >= K_{2*i+2}) i = 0,1,2…,则称为小堆(或大堆)

堆的两个重要性质

  • 堆中某个结点的值总是不大于或不小于其父结点的值;

  • 总是一棵完全二叉树

小根堆和大根堆 

根堆:树中所有的父节点的值都小于或等于孩子节点的值

根堆:树中所有的父节点的值都大于或等于孩子节点的值

如果树中所有的父节点的值都等于孩子节点的值,则既为小根堆又为大根堆

注:等定义中并没有规定左孩子和右节点的值的大小关系,因此堆不一定有序

6.堆的插入

由堆的简介可知:堆是一个完全二叉树,因此可以用顺序结构实现

以下方大根堆为例

现要尾插数字20,由存储结构可以看出:空间不够,要扩容

插入20前,找其父节点([\frac{child-1}{2}]=father),发现后者值为30,可以插入,仍然满足大根堆的性质 

再尾插入60

发现不满足大根堆的性质,需要一次调整

发现调整后仍然不满足大根堆的性质(56<60),需要再一次调整 

发现调整后满足大根堆的性质(56<60<70),结束

上述的调整起名为向上调整,最多调整h(二叉树的高度)次

7.堆的实现及操作堆的函数

以大根堆为例

堆的结构体定义

可以用结构体来定义堆,由于堆的底层是用数组存储的,因此三个成员变量:数据域,大小size,容量capacity

写入头文件中

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

堆初始化函数HeapInit

要想使用堆必须先初始化堆(malloc,对size和capacity初始化值)

void HeapInit(HP* php)
{
	assert(php);
	php->a = (HPDataType*)malloc(sizeof(HPDataType) * 4);
	if (php->a == NULL)
	{
		perror("malloc");
		return;
	}
	php->size = 0;
	php->capacity = 4;
}

php->capacity跟随malloc函数开辟空间的大小

堆插入元素函数HeapPush

插入前先判断空间是否充足,不够则relloc原来的2倍.之后调用向上调整函数进行插入

void HeapPush(HP* php, HPDataType x)
{
	assert(php);
	if (php->size == php->capacity)
	{
		HPDataType* tmp = (HPDataType*)realloc(php->a, sizeof(HPDataType) * php->capacity * 2);
		if (tmp == NULL)
		{
			perror("realloc");
			return;
		}
		php->a = tmp;
		php->capacity *= 2;
	}
	php->a[php->size] = x;//插入至数组的最后一个元素的下一个位置(size)
	php->size++;//数组大小+1

	//调用向上调整函数
	AdjustUp(php->a,php->size-1);
}

注意到AdjustUp传的第二个参数是php->size-1

堆向上调整函数AdjustUp

如果a[parent] < a[child],则进行交换,之后调整parent和child的值,以便于下一次调整

写法1

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 (a[parent] < a[child])
	{
		Swap(&a[parent], &a[child]);
        //调整parent和child的值
		child = parent;
		parent = (parent - 1) / 2;
	}
}

写法2

void AdjustUp(HPDataType* a, int child)
{
	int parent = (child - 1) / 2;
	while (parent>=0)
	{
		if (a[child] > a[parent])
		{
			Swap(&a[parent], &a[child]);
			child = parent;
			parent = (parent - 1) / 2;
		}
		else
		{
			break;
		}
	}
}

写法3

void AdjustUp(HPDataType* 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;
		}
	}
}

提问

已知这几种写法都能成功运行,哪个写法存在不规范的地方?

答:从特殊情况考虑问题,写法2:

当parent==0时,进入循环,若child==1,if判断成立,交换值后,child==0,parent==-1/2==0(取商)

while(parent>=0)条件仍然成立,但不满足if (a[child] > a[parent]),因此break

不规范的地方:child==parent==0就没有必要再次进入循环,建议改成while (child>0)(写法3)

测试堆插入函数

main.c手动写入插入一些随机值,以下代码,下断点至return 0;

#include "Heap.h"
int main()
{
	HP hp;
	HeapInit(&hp);
	HeapPush(&hp, 1);
	HeapPush(&hp, 3);
	HeapPush(&hp, 0);
	HeapPush(&hp, 5);
	HeapPush(&hp, 8);
	HeapPush(&hp, 12);
	HeapPush(&hp, 2);
	HeapPush(&hp, 5);
	HeapPush(&hp, 30);
	HeapPush(&hp, 50);
	return 0;
 }

打开监视窗口查看

画图后发现符合大根堆的性质

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

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

相关文章

CommonsBeanutils与Shiro发序列化利用的学习

一、前言 前面的学习中&#xff0c;过了一遍cc1-cc7的利用链&#xff0c;在CC2的利用链中&#xff0c;学习了 java.util.PriorityQueue&#xff0c;它在Java中是一个优先队列&#xff0c;队列中每一个元素都有自己的优先级。在反序列化这个对象时&#xff0c;为了保证队列顺序…

OpenGL入门008——环境光在片段着色器中的应用

本节将在片段着色器中应用环境光照(Ambient) 文章目录 一些概念光照模型环境光漫反射镜面反射总结 实战简介dependencieslightShader.vslightShader.fsshader.vsshader.fs utilsCube.hCube.cpp main.cppCMakeLists.txt最终效果 一些概念 光照模型 环境光 概述&#xff1a; 在…

cesium for unity的使用

先聊聊导入 看到这里的因该能够知道&#xff0c;官网以及网上绝大多数的方法都导入不进来&#xff0c;那么解决方法如下: 两个链接&#xff1a;按照顺序依次下载这两个tgz和zip&#xff0c;其中tgz为主要部分&#xff0c;zip为示例工程项目 如果您要查看示例工程项目的话&am…

stm32cubemx+VSCODE+GCC+makefile 开发环境搭建

title: stm32cubemxVSCODEGCCmakefile 开发环境搭建 tags: FreertosHalstm32cubeMx 文章目录 内容往期内容导航第一步准备环境vscode 插件插件配置点灯 内容 往期内容导航 第一步准备环境 STM32CubeMXVSCODEMinGWOpenOcdarm-none-eabi-gcc 然后把上面下载的软件 3 4 5 bin 文…

20241120-Milvus向量数据库快速体验

目录 20241120-Milvus向量数据库快速体验Milvus 向量数据库pymilvus内嵌向量数据库模式设置向量数据库创建 Collections准备数据用向量表示文本插入数据 语义搜索向量搜索带元数据过滤的向量搜索查询通过主键搜索 删除实体加载现有数据删除 Collections了解更多 个人主页: 【⭐…

【Axure高保真原型】3D农业管理大屏可视化案例

今天和大家分享3D农业管理大屏可视化案例的原型模板&#xff0c;里面包括重点指标分析、产量分析、种类分析、分布分析、收入分析和销售分析&#xff0c;具体效果可以点击下方视频观看或打开下方预览地址查看哦 【原型效果】 【Axure高保真原型】3D农业管理大屏可视化案例 【原…

使用 LSTM(长短期记忆网络) 模型对时间序列数据(航空旅客人数数据集)进行预测

代码功能 数据准备 加载数据&#xff1a;从公开的航空旅客人数数据集&#xff08;Airline Passengers Dataset&#xff09;中读取时间序列数据。 对数变换和平稳化&#xff1a;对数据应用 log1p 函数减少趋势和波动&#xff0c;使模型更容易学习规律。 归一化处理&#xff1a;…

Redis Search系列 - 第七讲 Windows(CygWin)编译Friso

目录 一、背景二、安装CygWin三、编译Friso四、运行Friso五、Friso分词效果测试 一、背景 最近在做RedisSearch的中文分词效果调研&#xff0c;底层的中文分词插件使用的就是Friso&#xff0c;目前手里的Linux环境上yum镜像仓库有问题导致没法安装gcc&#xff0c;又急于验证Fr…

【AI大模型引领变革】探索AI如何重塑软件开发流程与未来趋势

文章目录 每日一句正能量前言流程与模式介绍【传统软件开发 VS AI参与的软件开发】一、传统软件开发流程与模式二、AI参与的软件开发流程与模式三、AI带来的不同之处 结论 AI在软件开发流程中的优势、挑战及应对策略AI在软件开发流程中的优势面临的挑战及应对策略 结论 后记 每…

智领未来: 宏集物联网HMI驱动食品与包装行业迈向智能化新高度

行业现状与挑战 食品与包装行业对设备的自动化、智能化水平要求日益提高&#xff0c;特别是瓶装和灌装生产线需要实现高速、高效的生产。此外&#xff0c;该行业还需遵循严格的卫生标准和安全规范&#xff0c;以保证产品质量符合消费者需求。在提高生产效率的同时&#xff0c;…

LeetCode 热题100(九)【图论】(待更新)

目录 9.图论 9.1岛屿数量&#xff08;中等&#xff09; 9.2腐烂的橘子&#xff08;中等&#xff09; 9.3课程表&#xff08;中等&#xff09; 9.4实现 Trie (前缀树)&#xff08;中等&#xff09; 9.图论 9.1岛屿数量&#xff08;中等&#xff09; 题目描述&#xff1a;…

数据结构--跳表

跳表 原理实现 原理 跳表&#xff08;skiplist&#xff09;是一种链表&#xff0c;而链表查询的时间复杂度为O(n)&#xff0c;为了优化查询效率&#xff0c;我们可以让每相邻两个节点升高一层&#xff0c;增加一个指针&#xff0c;让指针指向下下个节点&#xff1a; 这样所有…

ChatGPT高级语音模式正在向Web网页端推出!

大家好&#xff0c;我是木易&#xff0c;一个持续关注AI领域的互联网技术产品经理&#xff0c;国内Top2本科&#xff0c;美国Top10 CS研究生&#xff0c;MBA。我坚信AI是普通人变强的“外挂”&#xff0c;专注于分享AI全维度知识&#xff0c;包括但不限于AI科普&#xff0c;AI工…

多传感器融合slam过程解析【大白话版】

SLAM&#xff08;同步定位与地图构建&#xff09;是自动驾驶、机器人导航和三维建模的关键技术之一。多传感器融合&#xff08;激光雷达、IMU、相机&#xff09;进一步提升了SLAM的鲁棒性和适应性&#xff0c;使其能够在复杂环境中实时构建高精度地图。本文将围绕激光雷达IMU相…

MySQL 中 InnoDB 支持的四种事务隔离级别名称,以及逐级之间的区别?

MySQL中的InnoDB存储引擎支持四种事务隔离级别&#xff0c;这些级别定义了事务在并发环境中的行为和相互之间的可见性。以下是这四种隔离级别的名称以及它们之间的区别&#xff1a; 读未提交&#xff08;Read Uncommitted&#xff09; 特点&#xff1a;这是最低的隔离级别&…

【Vue】Vue3.0(二十六)Vue3.0中的作用域插槽

上篇文章 【Vue】Vue3.0&#xff08;二十五&#xff09;Vue3.0中的具名插槽 的概念和使用场景 &#x1f3e1;作者主页&#xff1a;点击&#xff01; &#x1f916;Vue专栏&#xff1a;点击&#xff01; ⏰️创作时间&#xff1a;2024年11月20日17点30分 文章目录 概念使用场景示…

湘潭大学软件工程算法设计与分析考试复习笔记(四)

回顾 湘潭大学软件工程算法设计与分析考试复习笔记&#xff08;一&#xff09;湘潭大学软件工程算法设计与分析考试复习笔记&#xff08;二&#xff09;湘潭大学软件工程算法设计与分析考试复习笔记&#xff08;三&#xff09; 前言 现在是晚上十一点&#xff0c;我平时是十…

电路模型和电路定理(二)

电路元件 是电路中最基本的组成单元。 电阻元件&#xff1a;表示消耗电能的元件 电感元件&#xff1a;表示产生磁场&#xff0c;储存磁场能的元件 电容元件&#xff1a;表示产生电场&#xff0c;储存电场能量的元件 电压源和电流源&#xff1a;表示将其他形式的能量转变成…

【Golang】——Gin 框架中的 API 请求处理与 JSON 数据绑定

在现代 Web 开发中&#xff0c;API&#xff08;特别是 RESTful API&#xff09;是前后端分离架构的核心。Gin 框架提供了丰富的功能来处理 API 请求和 JSON 数据&#xff0c;使得开发者可以快速构建高效的接口服务。本篇博客将从基础到深入&#xff0c;全面讲解如何使用 Gin 框…

【STM32】时钟系统

在我们学习STM32之前&#xff0c;我们需要先了解STM32系列芯片的时钟系统&#xff0c;这个是我们学习这个芯片的基础。为什么时钟系统这么重要呢&#xff1f;举个例子&#xff0c;如果把STM32比作我们的整个人体&#xff0c;那么时钟就是维持我们人体正常工作的心脏。STM32芯片…