【算法与数据结构】深入解析二叉树(二)之堆结构实现

article/2025/8/14 21:02:14

请添加图片描述

文章目录

  • 📝二叉树的顺序结构及实现
    • 🌠 二叉树的顺序结构
    • 🌠 堆的实现
    • 🌠 堆的实现
      • 🌉堆向下调整算法
      • 🌉堆的创建
      • 🌉建堆时间复杂度
      • 🌉堆的插入
      • 🌉堆的删除
    • 🌠堆向上调整算法
      • 🌉堆的接口
    • 🌠堆的实现
    • 🌠堆的实现代码测试
  • 🚩总结


📝二叉树的顺序结构及实现

🌠 二叉树的顺序结构

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

🌠 堆的实现

堆(heap)是计算机科学中一类特殊的数据结构的统称。堆通常是一个可以被看做一棵树的数组对象。堆总是满足下列性质:
堆的物理结构本质上是顺序存储的,是线性的。但在逻辑上不是线性的,是完全二叉树的这种逻辑储存结构。 堆的这个数据结构,里面的成员包括一维数组,数组的容量,数组元素的个数,有两个直接后继。
堆的定义如下:n个元素的序列{k1,k2,ki,…,kn}当且仅当满足下关系时,称之为堆。
(且)或者(), ()
若将和此次序列对应的一维数组(即以一维数组作此序列的存储结构)看成是一个完全二叉树,则堆的含义表明,完全二叉树中所有非终端结点的值均不大于(或不小于)其左、右孩子结点的值。由此,若序列{k1,k2,…,kn}是堆,则堆顶元素(或完全二叉树的根)必为序列中n个元素的最小值(或最大值)。
在这里插入图片描述

将根结点最大的堆叫做最大堆或大根堆,根结点最小的堆叫做最小堆或小根堆。常见的堆有二叉堆、斐波那契堆等
堆的性质:

  • 堆中某个节点的值总是不大于或不小于其父节点的值;
  • 堆总是一棵完全二叉树。

🌠 堆的实现

🌉堆向下调整算法

现在我们给出一个数组,逻辑上看做一颗完全二叉树。我们通过从根节点开始的向下调整算法可以把它调整成一个小堆。向下调整算法有一个前提:左右子树必须是一个堆,才能调整。

int array[] = {27,15,19,18,28,34,65,49,25,37};

在这里插入图片描述

void AdjustDown(HPDataType* a, int n, int parent)
{int child = parent * 2 + 1;while (child < n){if (child+1<n && a[child + 1]>a[child]){child++;}if (a[child] > a[parent]){Swap(&a[child], &a[parent]);parent = child;child = parent * 2 + 1;}else{break;}}
}

🌉堆的创建

下面我们给出一个数组,这个数组逻辑上可以看做一颗完全二叉树,但是还不是一个堆,现在我们通过算法,把它构建成一个堆。根节点左右子树不是堆,我们怎么调整呢?这里我们从倒数的第一个非叶子节点的子树开始调整,一直调整到根节点的树,就可以调整成堆。

int a[] = {1,5,3,8,7,6};

在这里插入图片描述

代码:

int size=sizeof(array)/sizeof(int);
//向下建堆,复杂度为O(N)
for (int i = (size - 1 - 1) / 2; i >= 0; i--)
{AdjustDown(array, size,i);
}
void AdjustDown(HPDataType* a, int n, int parent)
{ //a是数组指针,n是数组长度,parent是当前需要下调的父结点索引int child = parent * 2 + 1;//child表示父结点parent的左孩子结点索引,因为是完全二叉堆,可以通过parent和2计算得到while (child < n){//如果左孩子存在if (child + 1 < n && a[child + 1] < a[child]){//如果右孩子也存在,并且右孩子值小于左孩子,则child指向右孩子child++;}if (a[child] < a[parent])//如果孩子结点值小于父结点值,则需要交换{Swap(&a[child], &a[parent]);//交换孩子和父结点parent = child;//父结点下移为当前孩子结点child = parent * 2 + 1;//重新计算新的左孩子结点索引}else{break;}}
}

这是向下调整,最终形成小根堆,如果你想修改大根堆只需改变两个代码方向即可:

if (child+1<n && a[child + 1]>a[child])
if (a[child] > a[parent])

🌉建堆时间复杂度

因为堆是完全二叉树,而满二叉树也是完全二叉树,此处为了简化使用满二叉树来证明(时间复杂度本来看的就是近似值,多几个节点不影响最终结果):

复杂度:O(N)
在这里插入图片描述

🌉堆的插入

先插入一个10到数组的尾上,再进行向上调整算法,直到满足堆。

在这里插入图片描述

void HPPush(HP* php, HPDataType x)
{assert(php);if (php->size == php->capacity){size_t newCapacity = php->capacity == 0 ? 4 : php->capacity * 2;HPDataType * tmp = realloc(php->a, sizeof(HPDataType) * newCapacity);if (tmp == NULL){perror("realloc fail");return;}php->a = tmp;php->capacity = newCapacity;}php->a[php->size] = x;php->size++;AdjustUp(php->a, php->size - 1);
}

🌉堆的删除

删除堆是删除堆顶的数据,将堆顶的数据根最后一个数据一换,然后删除数组最后一个数据,再进行向下调整算法。
在这里插入图片描述

//时间复杂度是:logN
void HPPop(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);
}

🌠堆向上调整算法

堆向上调整算法主要用于堆排序中,删除堆顶元素后,将最后一个元素补至堆顶,然后需要向上调整。

//向上调整,建堆O(N*logN)
for (int i = 1; i < size; i++)
{ //for循环从索引1开始,到size结束,即从第二个元素开始。AdjustUp(array, i);
}
void AdjustUp(HPDataType* a, int child)
{int parent = (child - 1) / 2;//计算父节点的位置:父节点位置 = (当前节点位置-1)/2while (child > 0)//如果当前节点位置大于0,并且当前节点值小于父节点值,需要向上调整:{if (a[parent] < a[child]){Swap(&a[parent], &a[child]);child = parent;parent = (parent - 1) / 2;}//将当前节点位置设为父节点的位置,重复执行步骤2和步骤3//直到当前节点位置为0,或者当前节点值不小于父节点值为止。else{break;}}
}

堆向上调整的主要步骤::确定需要调整的子节点,通常是补至堆顶的最后一个元素。
时间复杂度为O(N*logN)
在这里插入图片描述

🌉堆的接口

# define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>
#include<string.h>typedef int HPDataType;typedef struct Heap
{HPDataType* a;int size;int capacity;
}HP;void Swap(int* px, int* py);
void AdjustUp(HPDataType* a, int child);
void AdjustDown(HPDataType* a, int n, int parent);//堆的简单初始化
//void HPInit(HP* php);
//堆的初始化+建堆
void HPInitArray(HP* php, HPDataType* a, int n);
//堆的销毁
void HPDestroy(HP* php);
//堆插入数据然后保持数据是堆
void HPPush(HP* php, HPDataType x);
//取堆顶的数据
HPDataType HPTop(HP* php);
//删除堆数据
void HPPop(HP* php);
//堆的数据个数
int HeapSize(HP* php);
//堆的判空
bool HPEmpty(HP* php);

🌠堆的实现

#include"HeadSort.h"
//堆的简单初始化
void HPInit(HP* php)
{assert(php);php->a = NULL;php->size = 0;php->capacity = 0;
}void HPInitArray(HP* php, HPDataType* a, int n)
{assert(php);php->a = (HPDataType*)malloc(sizeof(HPDataType) * n);if (php->a == NULL){perror("malloc fail");return;}memcpy(php->a, a, sizeof(HPDataType) * n);php->capacity = php->size = n;//HPInitArray:/*初始化堆数组,并将数据拷贝过来有两种方式建堆:向上调整:每个节点都与父节点比较,时间复杂度O(NlogN)向下调整:从最后一个非叶子节点开	始,每个节点与子节点比较,时间复杂度O(N)这里采用向下建堆,复杂度更低*///向上调整,建堆O(N*logN)/*for (int i = 1; i < php->size; i++){AdjustUp(php->a, i);}*///向下建堆,复杂度为O(N)for (int i = (php->size - 1 - 1) / 2; i >= 0; i--){AdjustDown(php->a, php->size,i);}
}void HPDestroy(HP* php)
{assert(php);free(php->a);php->a = NULL;php->capacity = 0;php->size = 0;
}void Swap(int* px, int* py)
{int temp = *px;*px = *py;*py = temp;
}void AdjustUp(HPDataType* a, int child)
{int parent = (child - 1) / 2;while (child > 0){if (a[parent] > a[child]){Swap(&a[parent], &a[child]);child = parent;parent = (parent - 1) / 2;}else{break;}}
}void HPPush(HP* php, HPDataType x)
{assert(php);if (php->size == php->capacity){size_t newCapacity = php->capacity == 0 ? 4 : php->capacity * 2;HPDataType * tmp = realloc(php->a, sizeof(HPDataType) * newCapacity);if (tmp == NULL){perror("realloc fail");return;}php->a = tmp;php->capacity = newCapacity;}php->a[php->size] = x;php->size++;AdjustUp(php->a, php->size - 1);
}HPDataType HPTop(HP* php)
{assert(php);return php->a[0];}void AdjustDown(HPDataType* a, int n, int parent)
{int child = parent * 2 + 1;while (child < n){if (child+1<n && a[child + 1]<a[child]){child++;}if (a[child] < a[parent]){Swap(&a[child], &a[parent]);parent = child;child = parent * 2 + 1;}else{break;}}
}//时间复杂度是:logN
void HPPop(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);
}int HeapSize(HP* php)
{assert(php);return php->size;
}bool HPEmpty(HP* php)
{assert(php);return php->size == 0;
}

🌠堆的实现代码测试

int main()
{int a[] = { 60,70,65,50,32,100 };HP hp;HPInitArray(&hp, a, sizeof(a) / sizeof(int));/*HPInit(&hp);for (int i = 0; i < sizeof(a) / sizeof(int); i++){                         HPPush(&hp, a[i]);}printf("%d\n", HPTop(&hp));HPPop(&hp);printf("%d\n", HPTop(&hp));*/while (!HPEmpty(&hp)){printf("%d\n", HPTop(&hp));HPPop(&hp);}HPDestroy(&hp);return 0;
}

在这里插入图片描述


🚩总结

感谢你的收看,如果文章有错误,可以指出,我不胜感激,让我们一起学习交流,如果文章可以给你一个小小帮助,可以给博主点一个小小的赞😘

请添加图片描述


http://www.hkcw.cn/article/OORrmGelBr.shtml

相关文章

【leetcode】优先级队列的两种妙用:词频统计与动态中位数(附代码模板)

前言 &#x1f31f;&#x1f31f;本期讲解关于力扣的几篇题解的详细介绍~~~ &#x1f308;感兴趣的小伙伴看一看小编主页&#xff1a;GGBondlctrl-CSDN博客 &#x1f525; 你的点赞就是小编不断更新的最大动力 &#x1f386;那么废话不…

【算法学习】哈希表篇:哈希表的使用场景和使用方法

算法学习&#xff1a; https://blog.csdn.net/2301_80220607/category_12922080.html?spm1001.2014.3001.5482 前言&#xff1a; 在之前学习数据结构时我们就学习了哈希表的使用方法&#xff0c;这里我们主要是针对哈希表的做题方法进行讲解&#xff0c;都是leetcode上的经典…

HDFS详解

一、HDFS 概述 定位与特点 分布式文件系统&#xff1a;HDFS&#xff08;Hadoop Distributed File System&#xff09;是 Hadoop 生态的核心组件&#xff0c;专为海量数据存储和批处理设计。 核心设计原则&#xff1a; 高容错性&#xff1a;数据自动多副本冗余&#xff0c;支持…

【数据结构】String字符串的存储

目录 一、存储结构 1.字符串常量池 2.字符串哈希表 2.1结构 2.2基础存储单位 2.2.1键对象 2.2.2值对象 二、存储过程 1.搜索 2.创建 三、存储位置 四、存储操作 1.new新建 2.intern入池 这是String类的详解&#xff1a;String类变量 一、存储结构 1.字符串常量池…

数据结构大作业——家谱管理系统(超详细!完整代码!)

目录 设计思路&#xff1a; 一、项目背景 二、功能分析 查询功能流程图&#xff1a; 管理功能流程图&#xff1a; 三、设计 四、实现 代码实现&#xff1a; 头文件 结构体 函数声明及定义 创建家谱树头结点 绘制家谱树&#xff08;打印&#xff09; 建立右兄弟…

北京将有7级大风小冰雹 雷电蓝色预警发布

6月1日17时50分,北京发布雷电蓝色预警,预计当天20时至次日2时,自西向东将有雷阵雨天气,局地短时雨强较大,并伴有7级左右短时大风和小冰雹,请注意防范。明天上午至中午前后依旧会出现分散性雷阵雨,雨量总体不大。午后至前半夜北风增强,阵风明显,外出时请做好防风措施,…

专家:印太战略实质是霸权工具 不会得逞

针对美国防长赫格塞思在香格里拉对话会上涉及中国的部分表态,有中国学者指出,美国所谓的“印太战略”实质上是霸权工具,不会得逞。在对话会上,赫格塞思再次提到所谓的“印太战略”,并呼吁亚太地区同盟国和合作伙伴国与美国一起构筑更现实的战略关系。国防大学教授孟祥青表…

SCNN(Spatial CNN) 模型学习记录

目录 1.模型架构 2.核心模块SCNN_*分析 SCNN&#xff08;Spatial As Deep: Spatial CNN for Traffic Lane Detection&#xff09;是一种专为交通车道线检测任务设计的深度神经网络架构&#xff0c;由中国科学院计算技术研究所提出&#xff0c;旨在在语义分割框架中增强空间信…

Lerobot框架使用(含本地数据训练)

本文包含从安装环境到完整使用Lerobot框架进行算法复现全流程。 A Install LeRobot 安装miniconda管理python环境 Linux mkdir -p ~/miniconda3 wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh -O ~/miniconda3/miniconda.sh bash ~/minicon…

小红书 web x-s x-t X-Mns 分析

声明: 本文章中所有内容仅供学习交流使用&#xff0c;不用于其他任何目的&#xff0c;抓包内容、敏感网址、数据接口等均已做脱敏处理&#xff0c;严禁用于商业用途和非法用途&#xff0c;否则由此产生的一切后果均与作者无关&#xff01; 逆向分析 cp execjs.compile(open(v…

国产化中间件基本使用_东方通(TongWeb7.0.E.6_P2)

tongweb开发操作文档 1、前期准备 进入官网申请使用,官网地址:https://www.tongtech.com 若提供的安装程序的授权文件已过期,请去官方网站重新申请。 2、安装部署 2.1、下载安装Tongweb 进入官网申请试用,官方会提供响应的嵌入式安装包及试用授权证书(3个月) 申请…

010302-oss_反向代理_负载均衡-web扩展2-基础入门-网络安全

文章目录 1 OSS1.1 什么是 OSS 存储&#xff1f;1.2 OSS 核心功能1.3 OSS 的优势1.4 典型使用场景1.5 如何接入 OSS&#xff1f;1.6 注意事项1.7 cloudreve实战演示1.7.1 配置cloudreve连接阿里云oss1.7.2 常见错误1.7.3 安全测试影响 2 反向代理2.1 正向代理和反向代理2.2 演示…

FREERTOS+LWIP+IAP实现TCP、HTTP、网页访问并固件升级、更新配置 (三)lwip实现httpd服务并在web访问

前言 在前两篇文章中配置freeRTOS和&#xff0c;并实现了TCP、UDP的通信协议&#xff0c;现在终于轮到重头戏lwip的httpd服务&#xff0c;LWIP官方例程中是有很多自带的网页的&#xff0c;但是远远不够满足实际项目的使用需求&#xff0c;因此我也是踩了很多坑&#xff0c;从前…

lighthouse(灯塔)前端性能测试工具

前端性能测试工具之lighthouse灯塔 介绍下载链接使用方法前端性能指标解读 介绍 Lighthouse 是一个开源的自动化工具&#xff0c;用来测试前端页面性能&#xff0c;反馈页面问题以提升页面体验。可以联合谷歌浏览器&#xff0c;作为插件导入&#xff0c;开启后可测试页面性能 …

Ai智能体四:互动式 AI 聊天助手:前端实现

在现代 web 应用中,集成智能对话功能已经成为提升用户体验的重要手段之一。本文将介绍如何通过 Vue 3 和 Element Plus 构建一个高效的 AI 聊天助手界面,并详细讲解其实现原理和功能。 1. 整体架构 该聊天界面分为 左侧边栏 和 右侧内容区域,实现了清晰的布局结构,左侧边…

Spring Boot 3.x 引入springdoc-openapi (内置Swagger UI、webmvc-api)

接触的原因 因开发自己的项目时&#xff0c;写接口文档很繁琐&#xff0c;查到后端都在用swagger等接口工具来记录接口文档&#xff0c;于是学习了一下&#xff0c;本文记录个人配置过程&#xff0c;有问题欢迎指正交流&#x1f601; Swagger&#xff1a; Swagger是一种Rest AP…

OpenWebUI配置异常的外部模型导致页面无法打开

一、使用Ollama关闭OpenAI OpenWebUI自带OpenAI的API设置&#xff0c;且默认是打开的&#xff0c;默认情况下&#xff0c;启动后&#xff0c;会不断的去连https://api.openai.com/v1&#xff0c;但是无法连上&#xff0c;会报错&#xff0c;但是不会影响页面&#xff0c;能正常…

Postman(Apifox)调用WebServicer接口

postman调用WebServicer接口 前言 Postman使用方法Apifox使用方法参数与配置请求代码(当然一般开发会给一个样例)步骤 前言 之前都是使用SoapUI测试WebServicer接口,由于工作所需,需要使用Postman测试工具 Postman使用方法 可以直接在请求里写全部的wsdl地址 ,参数会自动带进…

DeepSeek本地化部署实践:Xinference框架+OpenWebUI实现DeepSeek-r1推理跑在国产GPU之上

近日&#xff0c;我部门从供应商那儿借来一台高算力服务器&#xff0c;用来尝试本地化部署DeepSeek。该服务器型号为ASUS ESC8000A-E11&#xff0c;具体配置如下&#xff1a; CPU&#xff1a;AMD EPYC 7702&#xff08;64核&#xff09;* 2 GPU&#xff1a;&#xff08;天数智…

Android WebRTC集成及JNI性能优化实战指南

本文还有配套的精品资源&#xff0c;点击获取 简介&#xff1a;WebRTC是一个开源项目&#xff0c;旨在实现浏览器间无需插件的实时通信&#xff0c;包括音频、视频通话及数据共享。在Android平台上&#xff0c;其实施涉及使用JNI接口进行Java与C/C代码的交互。本压缩包内容预…