二叉树顺序结构实现【堆的实现】【详细图解】

P. S.:以下代码均在VS2019环境下测试,不代表所有编译器均可通过。
P. S.:测试代码均未展示头文件stdio.h的声明,使用时请自行添加。

  

目录

  • 1、二叉树的顺序结构
  • 2、堆的概念
  • 3、堆的实现
    • 3.1 堆实现的前提
      • 3.1.1 向上调整
      • 3.1.2 向下调整
    • 3.2 堆实现
    • 3.2.1 数据插入
    • 3.2.2 数据删除
  • 4、完整代码展示
    • 4.1 Heap.h
    • 4.2 Heap.c
    • 4.3 Heaptest.c
  • 5、拓展堆排序
  • 6、结语





1、二叉树的顺序结构


  二叉树的顺序结构是指将数据以完全二叉树的逻辑结构进行存储的结构。
  但二叉树是多种多样的,为何在日常应用中很少见到普通的二叉树,且看下图中的普通二叉树与完全二叉树的展示。

在这里插入图片描述
  上图中左侧是一个普通的二叉树,右侧是一个完全二叉树(也可称之为满二叉树),当使用顺序结构进行存储时,可以发现作图的存储存在着大量的空间浪费,而右侧的完全二叉树却没有浪费很多空间。


  故在实现二叉树的顺序结构时所使用的是完全二叉树,而这一种存储方式,也称之为堆( PS. 此处的堆和操作系统虚拟进程地址空间中的堆是两回事,一个是数据结构,一个是操作系统中管理内存的一块区域分段)。




2、堆的概念


  若一组数据按照二叉树的顺序存储方式存储在一维数组中,就将其称作 “堆”
  堆也有大堆和小堆之分:
   大堆 :在二叉树中所有的父结点均比子结点所代表的数值大,称之为大堆。
   小堆 :在二叉树中所有的父结点均比子结点所代表的数值小,称之为小堆。
PS. 此处的大堆小堆是指父结点与子结点的大小关系,并不代表所存储数据在一维数组中一定有序。)


有关一维数组中如何寻找父子结点所在位置及其位置之间的关系,回看:
  链接: 数据结构—二叉树相关概念【详解】【画图演示】


有关树中结点之间的关系及其概念,回看:
  链接: 【树】简要理解树的概念




3、堆的实现


3.1 堆实现的前提


  在日常使用中,所输入数据之间维持大堆或小堆关系的情况较少出现,所以在输入数据时,一般需要使用向下调整或向上调整算法对所输入的数据大堆或小堆化,以便更好地使用。
  故在开始堆的实现前,需要先进行向上调整和向下调整算法的实现,后文命名为AdjustUp,AdjustDown。

3.1.1 向上调整


  向上调整是指每一次输入数据时,从输入数据位置作为子结点,与父结点进行比较,若子结点大于父节点,进行数值上的交换(此时构建的是大堆,反之构建的为小堆),交换后将此时的父结点看作新的子结点,再向上进行交换,直至到达根节点或出现子结点小于父结点为止。

在这里插入图片描述

  • 上图为输入28时所展现的向上调整示意图。

具体代码实现如下所示:

void AdjustUp(HPDataType* a, int child)
{int parent = (child - 1) / 2;while (child > 0){if (a[child] > a[parent]){Swap(&a[child], &a[parent]);child = parent;parent = (child - 1) / 2;}elsebreak;}
}
  • 代码块中所展示的Swap函数是一个简单的交换变量数值的函数。

3.1.2 向下调整


  向下调整的方式和向上调整的方式大致相同,以根作为父结点,与其两个子结点中最大的进行比较,若父结点所代表数值小于最大的子结点,则与之交换数值,而后以交换后的子结点作为新的父节点开启新一轮比较,直至出现父节点大于子结点的情况或到达叶子节点(此种方法所构建的是大堆,将上文中的比较词汇取反即可构建小堆)。

在这里插入图片描述

  • 上图中所展示的是通过向下调整构建小堆的过程。

具体代码如下所示:

void AdjustDown(HPDataType* a, int size, int parent)
{int child = parent * 2 + 1;while (child < size){if (child + 1 < size && a[child + 1] > a[child])//child + 1 < size 是为了避免子结点越界{++child;}if (a[child] > a[parent]){Swap(&a[child], &a[parent]);parent = child;child = parent * 2 + 1;}else{break;}}
}

3.2 堆实现


  因堆的实践中只有核心代码需要解释,其余部分代码将会在标题 4、完整代码展示 中展示。

3.2.1 数据插入


  
  • 结构体等相关定义展示
typedef int HPDataType;typedef struct Heap
{HPDataType* a;int size;int capacity;
}HP;void HPPush(HP* php, HPDataType x);

  因堆顺序结构的定义如上,且其中代表数组的是一个指向数据类型的指针,故我们需要进行数组的空间开辟,故出现了如下代码:

if (php->size == php->capacity){int newcapacity = php->capacity == 0 ? 4 : 2 * php->capacity;HPDataType* tmp = (HPDataType*)realloc(php->a, sizeof(HPDataType) * newcapacity);if (tmp == NULL){perror("HPPush:realloc fail");return;}php->a = tmp;php->capacity = newcapacity;}

  上图代码中我们需要先判断数组中的空间是否足够,即php->size == php->capacity,若判断条件成立,则进入扩容阶段,一般在扩容时我们会进行原有数组空间大小的二倍扩容,这一依据是根据相关研究者的研究所得出的结论,并应用realloc对原数组进行扩容。

  • 完整代码展示
void HPPush(HP* php, HPDataType x)
{assert(php);if (php->size == php->capacity){int newcapacity = php->capacity == 0 ? 4 : 2 * php->capacity;HPDataType* tmp = (HPDataType*)realloc(php->a, sizeof(HPDataType) * newcapacity);if (tmp == NULL){perror("HPPush:realloc fail");return;}php->a = tmp;php->capacity = newcapacity;}php->a[php->size] = x;php->size++;AdjustUp(php->a, php->size - 1);
}

  上述代码块中再插入数据后进行了向上调整,令所插入的数据形成大堆或小堆,以便后续使用。
  向上调整代码及原理回看3.1.1向上调整


3.2.2 数据删除


  数据删除阶段所删除的数据是根节点的数据,在直接删除根节点的数据后,堆中谁能作为新的根节点就成了不可避免的问题,为此可以直接将最后一位数据与第一位数据进行交换,再从根节点开始向下调整,这样就可以从堆中筛选出第二大或第二小的数据来作为新的根,并避免了不必要的麻烦。
  • 完整代码展示
void HPPop(HP* php)
{assert(php);assert(php->size > 1);Swap(&php->a[0], &php->a[php->size - 1]);php->size--;AdjustDown(php->a, php->size, 0);
}

  向下调整代码及原理回看3.1.2向下调整




4、完整代码展示

4.1 Heap.h

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <assert.h>typedef int HPDataType;typedef struct Heap
{HPDataType* a;int size;int capacity;
}HP;void Swap(HPDataType* p1, HPDataType* p2);void HPInit(HP* php);void HPDestroy(HP* php);void AdjustUp(HPDataType* a, int child);void HPPush(HP* php, HPDataType x);void AdjustDown(HPDataType* a, int size, int parent);void HPPop(HP* php);HPDataType HPTop(HP* php);bool HPEmpty(HP* php);int HPSize(HP* php);

4.2 Heap.c

#include "Heap.h"void Swap(HPDataType* p1, HPDataType* p2)
{HPDataType tmp = *p1;*p1 = *p2;*p2 = tmp;
}void HPInit(HP* php)
{assert(php);php->a = NULL;php->size = php->capacity = 0;
}void HPDestroy(HP* php)
{assert(php);free(php->a);php->a = NULL;php->size = php->capacity = 0;
}void AdjustUp(HPDataType* a, int child)
{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;}}
}void HPPush(HP* php, HPDataType x)
{assert(php);if (php->size == php->capacity){int newcapacity = php->capacity == 0 ? 4 : 2 * php->capacity;HPDataType* tmp = (HPDataType*)realloc(php->a, sizeof(HPDataType) * newcapacity);if (tmp == NULL){perror("HPPush:realloc fail");return;}php->a = tmp;php->capacity = newcapacity;}php->a[php->size] = x;php->size++;AdjustUp(php->a, php->size - 1);
}void AdjustDown(HPDataType* a, int size, int parent)
{int child = parent * 2 + 1;while (child < size){if (child + 1 < size && a[child + 1] > a[child]){++child;}if (a[child] > a[parent]){Swap(&a[child], &a[parent]);parent = child;child = parent * 2 + 1;}else{break;}}
}void HPPop(HP* php)
{assert(php);assert(php->size > 1);Swap(&php->a[0], &php->a[php->size - 1]);php->size--;AdjustDown(php->a, php->size, 0);
}HPDataType HPTop(HP* php)
{assert(php);assert(php->size > 0);return php->a[0];
}bool HPEmpty(HP* php)
{assert(php);return php->size == 0;
}int HPSize(HP* php)
{assert(php);return php->size;
}

4.3 Heaptest.c

#include "Heap.h"void test()
{HP s;HPInit(&s);HPPush(&s, 123);HPPush(&s, 12);HPPush(&s, 1);HPPush(&s, 321);HPPush(&s, 32);HPPush(&s, 3);printf("输入数据为:123,12,1,321,32,3\n");printf("插入数据后数组内成员展示:");for (int i = 0; i < s.size; i++){printf("%d ", s.a[i]);}printf("\n");HPPop(&s);HPPop(&s);printf("删除数据后数组内成员展示:");for (int i = 0; i < s.size; i++){printf("%d ", s.a[i]);}printf("\n");printf("此时调用判空函数后结果展示:");if (HPEmpty(&s))printf("yes\n");elseprintf("no\n");printf("此时数组内成员个数:");printf("%d\n", HPSize(&s));printf("此时根节点的数据为:");printf("%d\n", HPTop(&s));
}int main()
{test();return 0;
}




5、拓展堆排序


  堆排序的相关内容可以观看博主以往的博文:

    链接: 图解堆排序【一眼看穿逻辑思路】




6、结语


  十分感谢您观看我的原创文章。
  本文主要用于个人学习和知识分享,学习路漫漫,如有错误,感谢指正。
  如需引用,注明地址。

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

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

相关文章

采用java语言+B/S架构+后端SpringBoot前端Vue开发的ADR药品不良反应智能监测系统源码

采用java语言&#xff0b;B/S架构&#xff0b;后端SpringBoot前端Vue开发的ADR药品不良反应智能监测系统源码 ADR监测引擎每日主动获取检验数据、病历内容&#xff08;可拓展&#xff09;、以及其他临床数据&#xff0c;根据知识库内容自动判定患者是否有不良反应迹象&#xf…

【iOS】UI学习(一)

UI学习&#xff08;一&#xff09; UILabelUIButtonUIButton事件 UIViewUIView对象的隐藏UIView的层级关系 UIWindowUIViewController定时器与视图对象 UISwitch UILabel UILabel是一种可以显示在屏幕上&#xff0c;显示文字的一种UI。 下面使用代码来演示UILabel的功能&#…

做好开源快速开发平台研发创新 助力行业高效发展!

随着信息化时代的到来&#xff0c;科技的力量无处不在。为了提高办公效率&#xff0c;很多大中型企业倾向于使用更为先进的软件平台来助力企业降本增效。在众多助力神器之中&#xff0c;开源快速开发平台低代码技术平台深得广大新老客户朋友的喜爱&#xff0c;它与生俱来的优势…

Java数据类型

一、每种数据都定义了 明确的数据类型&#xff0c;在内存中分配了不同大小的 内存空间(字节)。 二、Java数据类型分为两种&#xff1a; 基本数据类型&#xff1a; 数值型&#xff1a; 整数类型&#xff0c;存放整数(byte[1] , short[2] , int[4] , long[8]) 浮点类型&#xff0…

UE5 读取本地图片并转换为base64字符串

调试网址&#xff1a;在线图像转Base64 - 码工具 (matools.com) 注意要加&#xff08;data:image/png;base64,&#xff09; FString UBasicFuncLib::LoadImageToBase64(const FString& ImagePath) {TArray<uint8> ImageData;// Step 1: 读取图片文件到字节数组if (!…

【蓝桥杯】第十四届蓝桥杯大赛软件赛国赛C/C++ 大学 B 组

答题结果页 - 蓝桥云课 (lanqiao.cn) 0子2023 - 蓝桥云课 (lanqiao.cn)&#xff08;暴力枚举 #include<bits/stdc.h> using lllong long; using ullunsigned long long; #define fir first #define sec second //#define int llconst int N1e510; const int mod1e97;int…

HT46R002 贴片 SOP8 经济型AD型OTP MCU单片机芯片

HT46R002在智能家居中的具体应用案例可以包括以下几个方面&#xff1a; 1. 智能照明控制&#xff1a;可以用于控制LED灯的亮度和色温&#xff0c;甚至可以通过手机APP远程控制开关和调节灯光效果。 2. 环境监测&#xff1a;用于监测室内温度、湿度、空气质量等&#xff0c;当检…

httpJVM

目录 HTTPS如何保证安全 1&#xff09;引入非对称加密 2&#xff09;引入非对称加密 3.中间人攻击 4.解决中间人攻击 JVM 1.JVM内存划分 2.JVM类加载过程 八股内容 3.JVM中的垃圾回收机制 释放垃圾的策略 1.标记-清除 2.复制算法 3.标记-整理 分代回收 HTTPS如何…

Android Graphics图形栈SurfaceFlinger之间各种Layer以及对应Buffer之间的关系

Android Graphics图形栈SurfaceFlinger之间各种Layer以及对应Buffer之间的关系 SurfaceFlinger layer之间的对应关系

MyBatis学习笔记(周五前学完)

MyBatis-Plus是一个MyBatis的增强工具。在MyBatis的基础上只做增强不做改变&#xff0c;为简化开发、提高效率而生。 通过MyBatis-Plus来进行数据插入时&#xff0c;它默认会 使用雪花算法来生成id&#xff0c;长度比较长 增删改的返回值都是统一的&#xff0c;影响的只有行数。…

给pdf加水印,python实现

from PyPDF2 import PdfReader, PdfWriterdef add_watermark(pdf_file_in, pdf_file_mark, pdf_file_out):"""把水印添加到pdf中"""pdf_output PdfWriter()input_stream open(pdf_file_in, rb)pdf_input PdfReader(input_stream, strictFalse…

基于魔搭开源推理引擎 DashInfer实现CPU服务器大模型推理--理论篇

前言 在人工智能技术飞速发展的今天&#xff0c;如何高效地在CPU上运行大规模的预训练语言模型&#xff08;LLM&#xff09;成为了加速生成式AI应用广泛落地的核心问题。阿里巴巴达摩院模型开源社区ModelScope近期推出了一款名为DashInfer的推理引擎&#xff0c;旨在解决这一挑…

机器学习补充学习

1、Adaboost算法 Adaboost算法是一种集成学习方法&#xff0c;通过结合多个弱学习器来构建一个强大的预测模型。核心思想&#xff1a;如果一个简单的分类器在训练数据上犯错误&#xff0c;那么它在测试数据上也可能犯错误。 Adaboost通过迭代地训练一系列的分类器&#xff0c…

QT-demo:0轴分布图表

版本&#xff1a;5.9 第一种: 使用 PyQt5 和 Matplotlib 库 安装所需的库&#xff1a; pip install PyQt5 matplotlib创建和显示图表&#xff1a; import sys import numpy as np import matplotlib.pyplot as plt from PyQt5.QtWidgets import QApplication, QMainWindow f…

【busybox记录】【shell指令】ln

目录 内容来源&#xff1a; 【GUN】【ln】指令介绍 【busybox】【ln】指令介绍 【linux】【ln】指令介绍 使用示例&#xff1a; 创建链接文件 - 链接文件&#xff08;默认 - 硬链接&#xff09; 创建链接文件 - 链接文件&#xff08;软链接&#xff09; 创建链接文件 -…

JeeSite 4.x and 5.x快速开发平台前端技术探索与实践

一、引言 随着企业信息化建设的不断推进&#xff0c;对于快速、高效、安全的企业级应用需求日益增长。JeeSite作为一款企业级快速开发平台&#xff0c;以其强大的后端功能和灵活的前端架构&#xff0c;为开发者提供了强大的支持。本文旨在探讨JeeSite快速开发平台在前端技术方…

新零售收银解决方案:传统门店超市的数字化-亿发

在数字化浪潮的推动下&#xff0c;零售行业正经历着前所未有的变革。阿里巴巴提出的“新零售”概念&#xff0c;不仅仅是一个商业口号&#xff0c;它代表了一种全新的商业模式和运营理念。随着时代的进步和消费需求的不断升级&#xff0c;新零售的兴起已成为行业发展的必然趋势…

学习笔记之——2D Gaussian Splatting(2DGS)

3DGS在辐射场重建中取得了巨大的成就&#xff0c;实现高质量的新视图合成和快速渲染。最近新出了3DGS的升级版本&#xff0c;2DGS。写下本博文记录本人学习及测试2DGS的过程&#xff0c;本博文仅为本人学习记录用~ Project WebsiteGithub CodeOriginal paper 目录 原理解读 …

企业级OV SSL证书的应用场景和加密手段

为了保护数据传输的安全性与用户隐私&#xff0c;企业级OVSSL&#xff08;Organization Validation SSL&#xff09;证书成为众多企业的首选安全解决方案。本文将深入探讨OVSSL证书的应用场景及其实现数据加密的核心手段&#xff0c;为企业构建坚不可摧的在线信任桥梁提供指南。…

YOLOv8+PyQt5车辆类型检测系统完整资源集合(yolov8模型,从图像、视频和摄像头三种路径识别检测,包含登陆页面、注册页面和检测页面)

资源包含可视化的车辆类型检测系统&#xff0c;基于最新的YOLOv8训练的车辆类型检测模型&#xff0c;和基于PyQt5制作的可视化车辆类型检测系统&#xff0c;包含登陆页面、注册页面和检测页面&#xff0c;该系统可自动检测和识别图片或视频当中出现的21种车辆类型&#xff0c;包…