二叉树顺序结构与堆的概念及性质(c语言实现堆)

news2025/1/20 1:50:25

上次介绍了树,二叉树的基本概念结构及性质:二叉树数据结构:深入了解二叉树的概念、特性与结构

今天带来的是:二叉树顺序结构与堆的概念及性质,还会用c语言来实现堆


文章目录

  • 1. 二叉树的顺序结构
  • 2.堆的概念和结构
  • 3.堆的实现(小堆)
    • 3.1项目文件规划
    • 3.2结构体和各功能一览(Heap.h)
    • 3.3重要函数详解(Heap.c)
      • 3.3.1堆向上调整算法
      • 3.3.2堆向下调整算法
    • 3.4各功能实现(Heap.c)
      • 初始化和销毁
      • 插入
      • 删除堆顶
      • 返回根(堆顶)的存储的数据
      • 节点数量
      • 是否为空
    • 3.5建堆时间复杂度


1. 二叉树的顺序结构

普通的二叉树是不适合用数组来存储的,因为可能会存在大量的空间浪费。完全二叉树就比较适合使用顺序结构存储(数组)。现实中我们通常把(一种二叉树)使用顺序结构的数组来存储

注意:此堆非“彼堆”——操作系统虚拟进程地址空间中的堆。二者一个是一个是数据结构,一个是操作系统中管理内存的一块区域


2.堆的概念和结构

堆需要满足两点

  1. 堆是一个完全二叉树,即除了最底层,其他层都是完全填满,最底层从左到右填充
  2. 堆中的每个节点的值都必须大于等于(最大堆)或小于等于(最小堆)其子节点的值

根据节点值的大小关系,堆可以分为最大堆和最小堆。在最大堆中,根节点的值最大,每个节点的值都大于等于其子节点的值。在最小堆中,根节点的值最小,每个节点的值都小于等于其子节点的值

请添加图片描述

请添加图片描述


3.堆的实现(小堆)

3.1项目文件规划

请添加图片描述

  • 头文件Heap.h:用来基础准备(常量定义,typedef),链表表的基本框架,函数的声明
  • 源文件Heap.c:用来各种功能函数的具体实现
  • 源文件test.c:用来测试功能是否有问题,进行基本功能的使用

3.2结构体和各功能一览(Heap.h)

typedef int HPDataType;

typedef struct Heap//用顺序表来实现,跟顺序表的结构一样
{
	HPDataType* a;
	int size;//数量
	int capacity;//容量
}HP;

void HeapInit(HP* php);//初始化
void HeapDestroy(HP* php);//销毁

void HeapPush(HP* php, HPDataType x);//插入
// 规定删除堆顶(根节点)
void HeapPop(HP* php);//删除

HPDataType HeapTop(HP* php);//返回根(堆顶)的存储的数据

int HeapSize(HP* php);//堆的数据个数

bool HeapEmpty(HP* php);//是否为空

3.3重要函数详解(Heap.c)

3.3.1堆向上调整算法

i位置节点的双亲序号:(i-1)/2

void Swap(HPDataType* p1, HPDataType* p2)
{
	HPDataType tmp = *p1;
	*p1 = *p2;
	*p2 = tmp;
}

void AdjustUp(HPDataType* a, int child)//传入数组和下标索引
{
	int father = (child - 1) / 2;//利用公式来算出父亲节点下标
	while (child > 0)
	{
		if (a[child] < a[father])
		{
			Swap(&a[child], &a[father]);
			//更新下标
			child = father;
			father = (father - 1) / 2;
		}
		else
		{
			break;//一旦符合小堆了,就直接退出
		}
	}
}

Swap 函数用于交换两个指针指向的值,而 AdjustUp 函数用于通过比较子节点与父节点并在有必要时交换它们来调整堆的结构,然后向上移动树,直到满足堆的性质

3.3.2堆向下调整算法

i位置的左孩子是 2 ∗ i + 1 2*i+1 2i+1,右孩子 2 ∗ i + 2 2*i+2 2i+2

void AdjustDown(HPDataType* a, int n, int father)
{
	int child = father * 2 + 1;//假设左孩子小  找出两者较小的来跟父节点比(大堆就找二者中较大的了)
	while (child < n)
	{
		if (child + 1 < n && a[child] > a[child + 1])
		{
			child++;
		}
		if (a[child] < a[father])
		{
			Swap(&a[child], &a[father]);
			father = child;
			child = father * 2 + 1;
		}
		else
		{
			break;
		}
	}
}
  1. 给定一个数组 a,表示堆的结构,以及数组的大小 n 和要进行调整的父节点的索引 father
  2. 计算父节点的左孩子的索引为 father * 2 + 1
  3. 进入一个 while 循环,只要左孩子的索引小于 n (不会出数组)就会继续
  4. 在循环内部,首先检查右孩子是否存在且右孩子的值是否大于左孩子的值,如果是,则更新 child 为右孩子的索引。这是为了找出左右孩子中值较大的那个
  5. 比较左孩子的值和父节点的值,如果左孩子的值小于父节点的值,则调用 Swap 函数交换这两个索引处的值,并更新 fatherchild 的值,然后重新计算 child 的索引。这一步的目的是将较大的子节点值向上移动,以满足堆的性质
  6. 如果左孩子的值不小于父节点的值,则跳出循环,因为堆的性质已经满足

3.4各功能实现(Heap.c)

初始化和销毁

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 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, newCapacity * sizeof(HPDataType));
		if (tmp == NULL)
		{
			perror("realloc fail");
			return -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);
	assert(php->size > 0);
	return php->a[0];
}

节点数量

int HeapSize(HP* php)
{
	assert(php);
	return php->size;
}

是否为空

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

	return php->size == 0;
}

3.5建堆时间复杂度

请添加图片描述

建堆的时间复杂度为O(N)


这次就到这里啦,下一次就利用这次的对来解决几个问题。感谢大家的支持!!!

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

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

相关文章

高光回眸:阿里云容器服务如何全面助力精彩亚运

作者&#xff1a;刘佳旭 谢乘胜 贤维 引言 2023 年&#xff0c;第 19 届杭州亚运会在杭州成功举办。在亚运之光和科技之光的交相辉映下&#xff0c;这届亚运会成为亚运史上首届“云上亚运”&#xff0c;用云计算创造了历史&#xff0c;赛事核心系统和转播全面上云&#xff0c…

leetcode贪心算法题总结(三)

本章目录 1.合并区间2.无重叠区间3.用最少数量的箭引爆气球4.整数替换5.俄罗斯套娃信封问题6.可被三整除的最大和7.距离相等的条形码8.重构字符串 1.合并区间 合并区间 class Solution { public:vector<vector<int>> merge(vector<vector<int>>&…

图像的颜色及Halcon颜色空间转换transfrom_rgb/trans_to_rgb/create_color_trans lut

图像的颜色及Halcon颜色空间转换 文章目录 图像的颜色及Halcon颜色空间转换一. 图像的色彩空间1. RGB颜色 2. 灰度图像3. HSV/ HSI二. Bayer 图像三. 颜色空间的转换1. trans_from_rgb算子2. trans_to_rgb算子3. create_color_trans_lut算子 图像的颜色能真实地反映人眼所见的真…

地震烈度速报与预警工程成功案例的经验分享 | TDengine 技术培训班第一期成功落地

近日&#xff0c;涛思数据在成都开设了“国家地震烈度速报与预警工程数据库 TDengine、消息中间件 TMQ 技术培训班”&#xff0c;这次培训活动共分为三期&#xff0c;而本次活动是第一期。其目标是帮助参与者深入了解 TDengine 和 TMQ 的技术特点和应用场景&#xff0c;并学习如…

Github 2023-12-30 开源项目日报 Top10

根据Github Trendings的统计&#xff0c;今日(2023-12-30统计)共有10个项目上榜。根据开发语言中项目的数量&#xff0c;汇总情况如下&#xff1a; 开发语言项目数量TypeScript项目4JavaScript项目2C项目1Python项目1Java项目1HTML项目1Dart项目1非开发语言项目1 令人惊叹的 …

(001)Unit 编译 UTF8JSON

文章目录 编译 Dll编译报错附录 编译 Dll 新建工程&#xff1a; 注意 UnityEngineDll 的选择&#xff01;2022 版本的太高了&#xff01;&#xff01;&#xff01; 下载包&#xff0c;导入unity : 3. 将 unf8json 的源码拷贝到新建的工程。 4. 编译发布版本&#xff1a; 编译…

浅层神经网络时间序列预测和建模

目录 时间序列网络 NARX 网络 NAR 网络 非线性输入-输出网络 定义问题 使用神经网络时间序列拟合时间序列数据 使用命令行函数拟合时间序列数据 选择数据 选择训练算法 创建网络 准备要训练的数据 划分数据 训练网络 测试网络 查看网络 分析结果 闭环网络 向…

数据的复制

基本概念 数据的复制指的是通过网络链接的多台机器保留相同的副本 为什么要进行数据的复制 使得用户和数据在地理上比较接近&#xff0c;因为大数据要求我们将计算安排在数据存放的位置和我们基本的内存模型不是很一样 &#xff0c;比如磁盘调入内存之类的。即使系统的一部分…

XTU-OJ-1452-完全平方数-笔记

参考博客 XTU-OJ 1452-完全平方数 题意 输入一个奇数&#xff0c;使得 n*(2*an-1)/2是一个完全平方数&#xff0c;求满足条件的最小的a 1<n<1e9 先输入样例数&#xff0c;再输入n 输入 2 1 3 输出 0 2 代码 #include<stdio.h>#define N 1000000010int a…

C#多条件排序OrderBy、ThenBy

方法和效果 有多个排序条件&#xff0c;其实不用单独自己写排序方法的&#xff0c;C#内置了排序方法&#xff1a; 引用命名空间System.Linq 正向排序的方法&#xff1a;OrderBy首要条件&#xff1b;ThenBy次要条件&#xff0c;可以连续多个使用 同理&#xff0c;逆向排序对应…

three.js绘制网波浪

无图不欢&#xff0c;先上图 使用方法&#xff08;以vue3为例&#xff09; <template><div class"net" ref"net"></div> </template><script setup> import { ref, onMounted } from vue import NetAnimation from /util…

面向搜索引擎优化初学者的 Google PageRank

即使你认为搜索已经摆脱了 PageRank 的影响&#xff0c;但时至今日&#xff0c;PageRank 很可能仍然存在于许多搜索巨头的系统中。 PageRank 曾经是搜索的核心&#xff0c;也是谷歌成为今天这个帝国的基础。 即使你认为搜索已经脱离了 PageRank&#xff0c;但不可否认的是&am…

阶段性复习(三)

if后面是赋值符&#xff0c;所以最后的值是a for&#xff08;&#xff1b; &#xff1b;&#xff09;是死循环 大小写转换 在这道题中&#xff0c;通过分析可知&#xff0c;在小写转换大写的过程中&#xff0c;需要满足的条件是word0&#xff0c;同时是小写&#xff0c;而在第…

Oracle 19c OCP 1z0 082考场真题解析第17题

考试科目&#xff1a;1Z0-082 考试题量&#xff1a;90 通过分数&#xff1a;60% 考试时间&#xff1a;150min 本文为云贝教育郭一军guoyJoe原创&#xff0c;请尊重知识产权&#xff0c;转发请注明出处&#xff0c;不接受任何抄袭、演绎和未经注明出处的转载。 17. Which three …

[C#]opencvsharp进行图像拼接普通拼接stitch算法拼接

介绍&#xff1a; opencvsharp进行图像拼一般有2种方式&#xff1a;一种是传统方法将2个图片上下或者左右拼接&#xff0c;还有一个方法就是融合拼接&#xff0c;stitch拼接就是一种非常好的算法。opencv里面已经有stitch拼接算法因此我们很容易进行拼接。 效果&#xff1a; …

Linux网络编程学习心得.5

1.libevent编写tcp服务器流程 创建套接字 绑定 监听 创建event_base根节点 初始化上树节点 lfd 上树 循环监听 收尾 普通的event事件 文件描述符 事件(底层缓冲区的读事件或者写事件) 触发 回调 高级的event事件 bufferevent事件 核心: 一个文件描述符 两…

【力扣题解】P654-最大二叉树-Java题解

&#x1f468;‍&#x1f4bb;博客主页&#xff1a;花无缺 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! 本文由 花无缺 原创 收录于专栏 【力扣题解】 文章目录 【力扣题解】P654-最大二叉树-Java题解&#x1f30f;题目描述&#x1f4a1;题解&#x1f30f;总结…

【Linux操作系统】探秘Linux奥秘:操作系统的入门与实战

&#x1f308;个人主页&#xff1a;Sarapines Programmer&#x1f525; 系列专栏&#xff1a;《操作系统实验室》&#x1f516;诗赋清音&#xff1a;柳垂轻絮拂人衣&#xff0c;心随风舞梦飞。 山川湖海皆可涉&#xff0c;勇者征途逐星辉。 目录 &#x1fa90;1 初识Linux OS …

【BERT】深入BERT模型2——模型中的重点内容,两个任务

前言 BERT出自论文&#xff1a;《BERT&#xff1a;Pre-training of Deep Bidirectional Transformers for Language Understanding》 2019年 近年来&#xff0c;在自然语言处理领域&#xff0c;BERT模型受到了极为广泛的关注&#xff0c;很多模型中都用到了BERT-base或者是BE…

Spring AOP<一>简介与基础使用

spring AOP 基础定义 含义使用切面组织多个Advice,Advice放在切面中定义。也就是说是定义通知的自定义类。自定义的AOP类Aspect连接点方法调用&#xff0c;异常抛出可以增强的点JoinPoint &#xff1a;也就是**被增强的方法的总称&#xff0c;可以获取具体方法的信息&#xff…