当前位置: 首页 > news >正文

【数据结构入门指南】二叉树顺序结构: 堆及实现(全程配图,非常经典)

【数据结构入门指南】二叉树顺序结构: 堆及实现(全程配图,非常经典)

  • 一、前言:二叉树的顺序结构
  • 二、堆的概念及结构
  • 三、堆的实现(本篇博客以实现小堆为例
    • 3.1 准备工作
    • 3.2 初始化
    • 3.3 堆的插入
      • 3.3.1 向上调整算法
    • 3.4 堆的删除
      • 3.4.1 向下调整算法
    • 3.5 堆的判空(<font color=orange>接下的过于简单直接给出带啊吗)
    • 3.6 取堆顶的数据
    • 3.7 堆的个数
    • 3.8 堆的销毁
  • 四、所有代码


在这里插入图片描述


一、前言:二叉树的顺序结构

普通的二叉树是不适合用数组来存储的,因为可能会存在大量的空间浪费。而完全二叉树更适合使用顺序结构存储。
 
现实中我们通常把堆(一种二叉树)使用顺序结构的数组来存储,需要注意的是这里的堆和操作系统虚拟进程地址空间中的堆是两回事,一个是数据结构,一个是操作系统中管理内存的一块区域分段。

在这里插入图片描述


二、堆的概念及结构

堆是一种特殊的数据结构,可以将堆分为大顶堆和小顶堆两种形式。堆中的每个节点都有一个值,并且满足以下两个条件:
 
①:堆的父节点的值总是大于或等于其子节点的值(大顶堆)或者小于或等于其子节点的值(小顶堆)。
②:堆是完全二叉树,即除了最底层外,其他层的节点都是满的,并且最底层的节点都尽量靠左排列。

大(小)堆示意图:

在这里插入图片描述
在这里插入图片描述


三、堆的实现(本篇博客以实现小堆为例

3.1 准备工作

由于堆是通过数组来实现的,所以我们也和顺序表一样,首先要创建一个结构体来存储:数组指针 + 容量 + 存储数据大小

代码实现:

typedef int HPDataType;
typedef struct Heap
{HPDataType* a;//数组指针int size;//存储数据大小int capacity;//容量
}HP;

3.2 初始化

初始化有两种方式:
①:初始化时为数组开辟一定大小空间。②:直接将数组指针置为NULL,插入数据过程中在进一步处理。(本篇博客采用第二种)

代码实现:

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

3.3 堆的插入

【代码思路】:
①:在插入数据前,我们首先要判断是否要扩容的问题。由于前面初始化时我们直接置空,所以我们先判断容量是否为空。如果为空开4个空间,否则空间扩大到原来的2倍。(为空时,第一次具体开辟多少空间读者可自行选择,本篇博客开4)
②:接下来就是插入数据了!但有一个问题,直接插入数据可能会破坏堆的结构,所以我们采用了向上调整算法

代码:

void HPPush(HP* php, HPDataType x)
{assert(php);//扩容if (php->size == php->capacity){int newcapacity = php->size == 0 ? 4 : php->capacity * 2;HPDataType* tmp = (HPDataType*)realloc(php->a,sizeof(HPDataType) * newcapacity);if (tmp == NULL){perror("malloc fail");exit(-1);}php->a = tmp;php->capacity = newcapacity;}//插入数据php->a[php->size] = x;php->size++;//向上调整AdjustUp(php->a, php->size - 1);
}

3.3.1 向上调整算法

【代码思路】:由于插入数据时,影响的只是插入数据到根节点间的关系。所以我们只需将插入数据通过双亲节点调到合适位置即可
 
Tips:父节点和子节点关系

  • leftchild = parent *2 + 1
  • rightchild = parent * 2 + 2
  • parent = (child - 1)/2

在这里插入图片描述
代码:

void Swap(HPDataType* p1, HPDataType* p2)
{HPDataType tmp = *p1;*p1 = *p2;*p2 = tmp;
}void AdjustUp(HPDataType* a, int child)
{assert(a);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;}		}
}

3.4 堆的删除

【代码思路】:堆的删除默认是头删。删除有两种思路:
 
①:将根节点删除,再将其余数据全部向前移动。但这样做会造成一个问题:挪动覆盖导致父子节点的关系全乱了,需要重新建堆。为了删个数据,重新建堆,得不偿失,所以我们采用下面这种方法。
 
②:将堆顶的1数据和最后一个数据交换,在删除最后一个数据。堆顶数据在通过向下调整算法调到合适位置即可

在这里插入图片描述

代码:

void HPPop(HP* php)
{assert(php);assert(!HPEmpty(php));//非空,还有数据可删。该接口后面实现Swap(&php->a[0], &php->a[php->size - 1]);//交换php->size--;//删除//向下调整AdjustDown(php->a, php->size, 0);
}

3.4.1 向下调整算法

【代码思路】:向下调整算法有一个前提:左右子树必须是一个堆,才能调整。同时还要注意是调大堆还是小堆。
调小堆:堆顶元素和孩子中最小的节点比较,如果父节点大于较小的子节点子,两者交换。不断向下调整到合适位置。(调大堆,和较大孩子比较)

在这里插入图片描述

代码

void AdjustDown(HPDataType* a, int n, int parent)
{assert(a);int child = parent * 2 + 1;//假设左孩子更小while (child < n){//如果有孩子存在,且有孩子更小,则左孩子加1移到右孩子if ((child + 1) < n && a[child] > a[child + 1]){child++;}if (a[parent] > a[child])//交换{Swap(&a[parent], &a[child]);parent = child;child = parent * 2 + 1;}else{//父节点小于较小的子节点,说明已经调到合适位置,此时break跳出break;}}
}

3.5 堆的判空(接下的过于简单直接给出带啊吗)

bool HPEmpty(HP* php)
{return php->size == 0;
}

3.6 取堆顶的数据

	assert(php);assert(!HPEmpty(php));//断言堆中还有元素return php->a[0];

3.7 堆的个数

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

3.8 堆的销毁

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

四、所有代码

Heap.h

#pragma once#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <stdbool.h>typedef int HPDataType;
typedef struct Heap
{HPDataType* a;int size;int capacity;
}HP;void HPInit(HP* php);//初始化
void HPPush(HP* php, HPDataType x);//插入数据
void HPPop(HP* php);//删除数据
int HPTop(HP* php);//堆顶元素
bool HPEmpty(HP* php);//判空
int HPSize(HP* php);//数据个数
void HPDestory(HP* php);//销毁

Heap.c

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

在这里插入图片描述
在这里插入图片描述

相关文章:

【数据结构入门指南】二叉树顺序结构: 堆及实现(全程配图,非常经典)

【数据结构入门指南】二叉树顺序结构: 堆及实现&#xff08;全程配图&#xff0c;非常经典&#xff09; 一、前言&#xff1a;二叉树的顺序结构二、堆的概念及结构三、堆的实现&#xff08;本篇博客以实现小堆为例&#xff09;3.1 准备工作3.2 初始化3.3 堆的插入3.3.1 向上调…...

css实现三角形的几种方法

css实现三角形的方法&#xff1a;1、使用边框实现三角形&#xff0c;利用透明边框和实色边框的组合&#xff0c;可以创建不同方向和大小的三角形&#xff1b;2、使用伪元素实现三角形&#xff0c;通过使用伪元素来创建一个占据父元素一半大小的实心三角形&#xff1b;3、使用tr…...

❤ Vue工作常用的一些动态数据和方法处理

❤ Vue工作常用的一些动态数据和方法处理 &#xff08;1&#xff09;动态拼接相对路径结尾的svg 错误写法一 ❌ 正确写法 &#x1f646; <img :src"require(/assets//amazon/svg/homemenu${index}.svg)" style"height: 20px;display: block;margin: 0 au…...

SQLite的命令用法

学习数据库直达网站 https://www.runoob.com/sqlite/sqlite-tutorial.html&#xff08;菜鸟教程&#xff09; 这里只分享&#xff0c;基础操作&#xff0c;数据库创建打开……等等 用到查菜鸟教程即可 文章目录 学习数据库直达网站创建一个数据库方式1方式2 创建一个表格插入一…...

在jupyter notebook中使用海龟绘图

首先&#xff0c;安装ipyturtle3 ref:ipyturtle3 PyPI pip install ipyturtle3然后&#xff0c;安装ipycanvas ipycanvas是一个需要安装在与JupyterLab实例相同环境的包。此外&#xff0c;您需要安装nodejs&#xff0c;并启用JupyterLab ipycanvas小部件。 所有这些都在ipy…...

密码学学习笔记(十八):Diffie–Hellman (DH) 密钥交换

DH算法是第一个密钥交换算法&#xff0c;也是第一个得到形式化描述的公钥密码算法。 群论 DH密钥交换算法基于数学中的群论&#xff0c;群论也是当今大多数公钥密码的基础。 要使集合及其运算成为一个群&#xff0c;需要满足以下性质&#xff1a; 封闭性&#xff1a;群中两…...

Linux —— 进程间通信(管道)

目录 一&#xff0c;进程间通信 二&#xff0c;管道 匿名管道 命名管道 一&#xff0c;进程间通信 进程间通信&#xff08;IPC&#xff0c;InterProcess Communication&#xff09;&#xff0c;即在不同进程之间进行信息的传播或交换&#xff1b;由于一般进程用户地址空间是…...

python常用

环境配置 conda Conda自动补全 在终端激活conda环境的时候按tab不能自动补全activate和环境名。安装后可用tab进行补全。 安装 conda-bash-completion 插件&#xff1a;GitHub 安装方法&#xff1a; conda install -c conda-forge conda-bash-completion常用命令 #创建虚拟…...

jeecg如何创建报表并配置到菜单中

当使用jeecg创建单表之后,需要进行报表显示,并把报表配置到菜单中,该如何操作呢?下面进行详细讲解。这里以课程表这张表为例进行讲解。 一.表单创建完成,并配置好菜单栏。具体步骤略,如下图: 二.创建积木报表 1.左侧边栏展开低代码开发菜单,进入报表设计器栏目 2.进…...

Servlet+JDBC实战开发书店项目讲解第12讲:会员管理功能

ServletJDBC实战开发书店项目讲解第12讲&#xff1a;会员管理功能 实现思路&#xff1a; 显示会员列表&#xff1a; 创建一个管理页面&#xff0c;用于显示所有会员的信息。在后端&#xff0c;创建一个Servlet来处理显示会员列表的请求。在该Servlet中&#xff0c;通过JDBC从数…...

java面向对象——继承以及super关键字

继承的概念 1. 被继承的类称为父类&#xff08;超类&#xff09;&#xff0c;继承父类的类都称为子类&#xff08;派生类&#xff09; 2. 继承是指一个对象直接使用另一个对象的属性和方法&#xff0c;但是能继承非私有的属性和方法&#xff1b;(1) 构造方法不能被继承。(2) 但…...

[机缘参悟-101] :IT人 - 遵从世界本源的样子,不带个人情感、道德、认知倾向,接纳一切,你就拥有无限的力量

目录 道的本义 如来的本义 观音的本义 无为而治本质是顺势而为 儒家的本质 感悟&#xff1a; 道的本义本质&#xff1a;天地的力量和运行规律 "天地以万物为刍狗"是出自《道德经》第五十章的一句话。在这句话中&#xff0c;"天地"指的是宇宙&#x…...

C++--深度理解智能指针

PS:智能指针简单应用看这里 http://t.csdn.cn/qN7IK 1.智能指针的介绍 在C中&#xff0c;智能指针有三个版本&#xff0c;分别为&#xff1a; auto_ptr unique_ptr shared_ptr 这三个版本的智能指针中&#xff0c;shared_ptr最为完善&#xff0c;auto_ptr基本上没有太大用…...

Spring Boot使用MySQL的默认连接池

笔者在近期秋招面试的时候被问到了这个问题&#xff0c;现在简单梳理一下便于后期重新回顾&#xff0c;并加深记忆。 Spring Boot 默认使用的数据库连接池是 HikariCP(开源库地址)。 HikariCP 是目前性能最好的连接池之一&#xff0c;它具有高度的性能、可靠性和可扩展性&…...

conda使用教程

Conda介绍 conda可以理解为一个工具&#xff0c;也是一个可执行命令&#xff0c;其核心功能是包管理和环境管理。包管理与pip的使用方法类似似&#xff0c;环境管理则是允许用户方便滴安装不同版本的python环境并在不同环境之间快速地切换。 conda的设计理念 conda将几乎所有…...

什么是LLM大语言模型?

什么是LLM大语言模型&#xff1f; 大语言模型&#xff08;英文&#xff1a;Large Language Model&#xff0c;缩写LLM&#xff09;&#xff0c;也称大型语言模型&#xff0c;是一种人工智能模型&#xff0c;旨在理解和生成人类语言。它们在大量的文本数据上进行训练&#xff0…...

jenkins同一jar包部署到多台服务器

文章目录 安装插件配置ssh服务构建完成后执行 没有部署过可以跟这个下面的步骤先部署一遍&#xff0c;我这篇主要讲jenkins同一jar包部署到多台服务器 【Jenkins】部署Springboot项目https://blog.csdn.net/qq_39017153/article/details/131901613 安装插件 Publish Over SSH 这…...

(四)Doceke安装MySQL镜像+Docker启动MySQL容器

Doceke安装MySQL镜像/Docker启动MySQL容器 一、doceke安装MySQL镜像 切换到root用户&#xff0c;su root 。 1、启动Docker 启动&#xff1a;sudo systemctl start docker 停止&#xff1a;systemctl stop docker 重启&#xff1a;systemctl restart docker 查看docker运行…...

Android Studio:Could not initialize class org.codehaus.groovy.vmplugin.v7.Java7

原项目使用jdk8&#xff0c;升级gradle后出现的该问题。 java.lang.NoClassDefFoundError: Could not initialize class org.codehaus.groovy.vmplugin.v7.Java7at org.codehaus.groovy.vmplugin.VMPluginFactory.<clinit>(VMPluginFactory.java:43)at org.codehaus.gro…...

Spring Clould 搜索技术 - elasticsearch

视频地址&#xff1a;微服务&#xff08;SpringCloudRabbitMQDockerRedis搜索分布式&#xff09; 初识ES-什么是elasticsearch&#xff08;P77&#xff0c;P78&#xff09; 1.elasticsearch的作用 elasticsearch是一款非常强大的开源搜索引擎&#xff0c;具备非常多强大功能…...

FPGA状态机实战:用Verilog实现自动售卖机(附三段式完整代码)

FPGA状态机实战&#xff1a;用Verilog实现自动售卖机&#xff08;附三段式完整代码&#xff09; 在数字电路设计中&#xff0c;状态机是最核心的设计思想之一。它能够将复杂的控制逻辑分解为有限的状态和状态之间的转换&#xff0c;使得设计更加清晰、可维护。自动售卖机作为一…...

ARMv8、AArch64 与 arm64:命名与体系结构要点

ARMv8、AArch64 与 arm64&#xff1a;命名与体系结构要点 ARMv8 指 ARM 架构的一个主版本代际&#xff1b;AArch64 是该代际下的 64 位执行状态与 A64 指令集&#xff1b;arm64 与 aarch64 是操作系统与工具链中对 AArch64 的常用三元组/目录名&#xff0c;二进制约定一致。下…...

SDMatte在电商场景落地:商品主图自动去背景+透明PNG生成完整工作流

SDMatte在电商场景落地&#xff1a;商品主图自动去背景透明PNG生成完整工作流 1. 电商场景中的图像处理痛点 在电商运营中&#xff0c;商品主图的质量直接影响转化率。传统处理方式面临三大难题&#xff1a; 人工成本高&#xff1a;专业设计师处理一张图平均耗时15-30分钟边…...

Matlab 实现 DES 与 RSA 双重加密及可视化界面搭建

基于matlab上的DES和RSA两种算法的双重加密&#xff0c;附带显示界面&#xff0c;可更改DES密钥&#xff0c;明文消息&#xff08;在显示界面中&#xff09;&#xff0c;可在代码中更改RSA对应的p&#xff0c;q&#xff0c;e等数据&#xff0c;代码可附加注释和对应要求修改。在…...

Gemma-3-270m量化压缩实战:4位精度模型部署

Gemma-3-270m量化压缩实战&#xff1a;4位精度模型部署 1. 开篇&#xff1a;小模型的大能量 最近在折腾边缘设备部署时&#xff0c;发现一个挺有意思的现象&#xff1a;很多团队还在用"大炮打蚊子"&#xff0c;明明只需要处理一些简单的文本分类任务&#xff0c;却…...

DeepSeek-OCR-2实战案例:高校教务系统成绩单OCR+学分绩点自动计算

DeepSeek-OCR-2实战案例&#xff1a;高校教务系统成绩单OCR学分绩点自动计算 本文介绍如何利用DeepSeek-OCR-2模型实现高校教务系统成绩单的OCR识别&#xff0c;并结合vLLM推理加速和Gradio前端展示&#xff0c;构建一个完整的成绩单识别与学分绩点自动计算系统。 1. 项目背景与…...

如何用torchtext快速构建文本分类模型?5分钟上手RoBERTa与T5实战教程

如何用torchtext快速构建文本分类模型&#xff1f;5分钟上手RoBERTa与T5实战教程 【免费下载链接】text Models, data loaders and abstractions for language processing, powered by PyTorch 项目地址: https://gitcode.com/gh_mirrors/te/text 想要在PyTorch生态中快…...

终极指南:如何使用Cat-Catch浏览器资源嗅探工具轻松捕获网络媒体资源

终极指南&#xff1a;如何使用Cat-Catch浏览器资源嗅探工具轻松捕获网络媒体资源 【免费下载链接】cat-catch 猫抓 chrome资源嗅探扩展 项目地址: https://gitcode.com/GitHub_Trending/ca/cat-catch Cat-Catch&#xff08;猫抓&#xff09;是一款强大的浏览器资源嗅探扩…...

OpenClaw安全实践:私有化Qwen3-VL:30B保障敏感数据不出境

OpenClaw安全实践&#xff1a;私有化Qwen3-VL:30B保障敏感数据不出境 1. 为什么我们需要私有化部署 去年处理一份法律合同时&#xff0c;我犯了一个至今心有余悸的错误——把客户保密协议上传到某公有云AI进行条款分析。虽然及时删除了文件&#xff0c;但那种"数据已脱离…...

League Akari:5大核心解决方案提升英雄联盟游戏体验

League Akari&#xff1a;5大核心解决方案提升英雄联盟游戏体验 【免费下载链接】League-Toolkit 兴趣使然的、简单易用的英雄联盟工具集。支持战绩查询、自动秒选等功能。基于 LCU API。 项目地址: https://gitcode.com/gh_mirrors/le/League-Toolkit League Akari是一…...