数据结构:二叉树的数组结构以及堆的实现详解

目录

一.树与二叉树

1.树的概念与相关术语:

2.二叉树:

(1)定义:

(2)特殊的二叉树:

(3)完全二叉树

(4)二叉树的存储结构:

二.堆的概念与性质

1.堆的概念:

2.堆的重要性质:

三.堆的具体代码实现

1.堆的结构:

2.堆的初始化与销毁:

3.向上调整算法和向下调整算法:

(1)向上调整算法:

(2)向下调整算法:

(3)总结两种算法的区别:

(4)堆元素的插入:

(5)堆元素的删除:

(6)取堆顶元素:

(7)堆的判空:

四.堆的具体应用

1.基于已有堆结构的堆排序(通过不断取堆顶):

2.数组建堆,先向下调整建堆,再向上调整:


一.树与二叉树

1.树的概念与相关术语:

     概念

       树是⼀种非线性的数据结构,它是由 n(n>=0) 个有限结点组成⼀个具有层次关系的集合。把它叫做 树是因为它看起来像⼀棵倒挂的树,也就是说它是根朝上,而叶朝下的。

        有一个特殊的结点,称为根结点,根结点没有前驱结点。

         除根结点外,其余结点被分成 M(M>0) 个互不相交的集合 T1、T2、……、Tm ,其中每⼀个集合 Ti( 又是⼀棵结构与树类似的子树。每棵⼦树的根结点有且只有⼀个前驱,可以 有 0 个或多个后继。因此,树是递归定义的

相关术语

父结点/双亲结点:若⼀个结点含有子结点,则这个结点称为其子结点的父结点

子结点/孩子结点:⼀个结点含有的⼦树的根结点称为该结点的⼦结点

结点的度:⼀个结点有⼏个孩⼦,他的度就是多少

树的度:⼀棵树中,最⼤的结点的度称为树的度

叶子结点/终端结点:度为 0 的结点称为叶结点

分支结点/非终端结点:度不为 0 的结点

兄弟结点:具有相同父结点的结点互称为兄弟结点(亲兄弟)

结点的层次:从根开始定义起,根为第 1 层,根的⼦结点为第 2 层,以此类推

树的高度或深度:树中结点的最大层次

路径:⼀条从树中任意节点出发,沿父节点-子节点连接,达到任意节点的序列

2.二叉树:

(1)定义:

二叉树满足以下两个特点:

       1. 二叉树不存在度大于 2 的结点

       2. 二叉树的子树有左右之分,次序不能颠倒,因此⼆叉树是有序树

2)特殊的二叉树:

 满二叉树
        ⼀个二叉树,如果每⼀个层的结点数都达到最⼤值,则这个二叉树就是满二叉树。也就是说,如果⼀ 个二叉树的层数为 K ,且结点总数是2的k次方-1 ,则它就是满二叉树。

(3)完全二叉树

        完全二叉树是效率很高的数据结构,完全二叉树是由满⼆叉树而引出来的。

        对于深度为 K 的,有 n 个 结点的⼆叉树,当且仅当其每⼀个结点都与深度为K的满⼆叉树中编号从 1 至 n 的结点⼀⼀对应时称 之为完全⼆叉树。要注意的是满⼆叉树是⼀种特殊的完全⼆叉树

                                   

简单来说:完全二叉树和满二叉树的区别·就在于那它们的区别主要在于结构上的差异,满二叉树要求每一层都填满,而完全二叉树只要求前几层填满最后一层可以填到最左边但不一定全部填满

(4)二叉树的存储结构:

顺序存储(即下面我要说的堆链式结构

(我在这篇文章主要说明的是二叉树的顺序存储,链式结构的介绍我会详细再另外写一篇文章)


二.堆的概念与性质

1.堆的概念:

     堆(Heap)是计算机科学中的一种特殊数据结构,它可以被视为一棵完全二叉树的数组表示形式。堆的特点是节点的值总是不大于或不小于其父节点的值,这种性质使得堆的根节点总是该数据结构中的最大值或最小值

     其中,堆的根节点是该数据结构中的最大值则称该堆为大根堆

     堆的根节点是该数据结构中的最小值则称该堆为小根堆

     堆满足以下特性:

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

*堆总是⼀棵完全二叉树

2.堆的重要性质:

对于具有 n 个结点的完全⼆叉树,如果按照从上至下从左至右的数组顺序对所有结点从 0 开始编号,则对于序号为 i 的结点有:

        1. 若 i>0 , i 位置结点的双亲序号: (i-1)/2 ; i=0 , i 为根结点编号,无双亲结点

        2. 若 2i+1,左孩子序号: 2i+1 , 2i+1>=n 否则无左孩子

        3. 若 2i+2,右孩子序号: 2i+2 , 2i+2>=n 否则无右孩子


三.堆的具体代码实现

1.堆的结构:

//堆的结构
typedef int HPDataType;
typedef struct Heap
{HPDataType* arr;int size;//有效数据个数int capacity;//空间大小
}HP;

2.堆的初始化与销毁:

//堆的初始化
void HPInit(HP* php)
{assert(php);php->arr = NULL;php->size = php->capacity = 0;
}//堆的销毁
void HPDestroy(HP* php)
{assert(php);if (php->arr){free(php->arr);}php->arr = NULL;php->capacity = php->size = 0;
}

3.向上调整算法和向下调整算法:

(1)向上调整算法:

目标

将新插入的节点或被修改的子节点调整到合适位置,使其满足堆性质
步骤
从当前节点开始,比较其与父节点的值
如果违反堆性质(如最小堆中子节点值更小),则交换两者
重复上述过程,直到到达根节点或满足堆性质

void AdjustUp(HP* hp, int child)//传入堆和调整的起始孩子
{int parent = (child - 1) / 2;//公式while (child > 0)//注意退出条件{//建小根堆if (hp->arr[parent] > hp->arr[child]){swap(&hp->arr[parent], &hp->arr[child]);child = parent;parent = (child - 1) / 2;}else{break;//如果不用换了。说明这个堆正常了,和adjustdown的退出原因一样}}
}
(2)向下调整算法:

目标

将删除根节点后的最后一个元素调整到堆顶,或修复被修改的根节点
步骤
找到当前节点的子节点(左、右),选出符合堆性质的子节点(如最小堆中较小的子节点)
如果当前节点违反堆性质(如比子节点更大),则与子节点交换
重复上述过程,直到叶子节点或满足堆性质

void AdjustDown(HP* hp, int parent, int n)//n是向下调整的下界范围
{int child = parent * 2 + 1;//公式while (child < n){//建小根堆if (child + 1 < n && hp->arr[child + 1] < hp->arr[child])//child+1的目的是确保两个孩子结点都是有意义的结点{child++;}if (hp->arr[parent] > hp->arr[child]){swap(&hp->arr[parent], &hp->arr[child]);parent = child;child = parent * 2 + 1;}else{//我最小的孩子都比父节点大,那么这个堆就是正常堆了,直接退出break;}}
}
(3)总结两种算法的区别:

1. 方向不同
向上调整:

从子节点向根节点方向调整
例如,插入新节点时,将其放在堆末尾,然后逐层与父节点比较并交换
向下调整:

从父节点向叶子节点方向调整
例如,删除根节点后,将末尾节点移到根位置,逐层与子节点比较并交换

2. 应用场景不同
向上调整:
插入新元素:新元素被添加到堆的末尾,可能破坏堆性质,需向上调整
节点值增大:在最大堆中,若某节点的值变大,可能需要向上调整
向下调整
删除根节点:删除堆顶后,将末尾节点移到堆顶,需向下调整
节点值减小:在最大堆中,若某节点的值变小,可能需要向下调整
构建堆:从最后一个非叶子节点开始,逐个向下调整,时间复杂度为 O(n)


3. 操作步骤不同
向上调整:
比较当前节点与父节点
若违反堆性质(如最大堆中当前节点值更大),则交换两者
重复直到到达根节点或满足堆性质
向下调整:
比较当前节点与左右子节点
选择最大(或最小)的子节点(根据堆类型)
若子节点违反堆性质,则交换两者
重复直到到达叶子节点或满足堆性质


4. 时间复杂度
常数因子差异:向下调整需比较两个子节点,操作略复杂;向上调整仅需比较父节点

以下是时间复杂度的具体算法

(4)堆元素的插入:
void HeapPush(HP* hp, int x)
{assert(hp);//判断空间是否已满if (hp->capacity == hp->size){//注意capacity的单位是个,不是字节int newcapacity = hp->capacity == 0 ? 4 : 2 * hp->capacity;//第一次开就开四个//空间开辟//注意这里是realoc不是malloc//所有链式结构的用malloc,咱们开辟新节点//所有线性结构,底层是数组的,咱们就realoc//因为咱们要保留数组之前的数据,所以必须要扩容而不是重新开辟HP* newspace = (HP*)realloc(hp->arr, newcapacity * sizeof(int));if (newspace == NULL){perror("malloc wrong!");exit(1);}hp->arr = newspace;hp->capacity = newcapacity;}//直接插入//size是当前有效元素个数,对应的也是下一个该存放元素位置的下标hp->arr[hp->size] = x;hp->size++;//插入元素之后配套进行向上调整AdjustUp(hp, hp->size - 1);//注意传入的是下标
}
(5)堆元素的删除:
void HeapPop(HP* hp)
{//几乎所有的数据结构,在插入元素是要断言这个数据结构是否存在//在删除元素的时候断言这个数据结构中要含有元素assert(!empty(hp));//删除根元素swap(&hp->arr[0], &hp->arr[hp->size - 1]);hp->size--;//配套使用向下调整算法AdjustDown(hp, 0, hp->size);
}
(6)取堆顶元素:
int HeapTop(HP* hp)
{assert(!empty(hp));//empty里面判断了这个堆必须存在,所以说不用再在这判断了、return hp->arr[0];
}
(7)堆的判空:
bool empty(HP* hp)
{assert(hp);return hp->size == 0;
}

四.堆的具体应用

1.基于已有堆结构的堆排序(通过不断取堆顶):

// 1、需要堆的数据结构
// 2、空间复杂度 O(N)
void HeapSort(int* a, int n)
{HP hp;for(int i = 0; i < n; i++){HPPush(&hp,a[i]);}int i = 0;while (!HPEmpty(&hp)){a[i++] = HPTop(&hp);HPPop(&hp);}HPDestroy(&hp);
}

2.数组建堆,先向下调整建堆,再向上调整:

// 升序,建⼤堆
// 降序,建⼩堆
// O(N*logN)
void HeapSort(int* a, int n)
{// a数组直接建堆 O(N)for (int i = (n-1-1)/2; i >= 0; --i){AdjustDown(a, n, i);}// O(N*logN)int end = n - 1;while (end > 0){Swap(&a[0], &a[end]);AdjustDown(a, end, 0);--end;}
}

欧克,到这里就差不多把数组结构的堆介绍完了,更多的就是堆的Top-K问题了,感兴趣的可以先去了解,我后续会写关于它的解析

那就这样吧

全文终

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

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

相关文章

Python 函数式编程-偏函数

目录 偏函数 小结 偏函数 Python的functools模块提供了很多有用的功能&#xff0c;其中一个就是偏函数&#xff08;Partial function&#xff09;。要注意&#xff0c;这里的偏函数和数学意义上的偏函数不一样。 在介绍函数参数的时候&#xff0c;我们讲到&#xff0c;通过…

鸿蒙中连接手机可能遇到的问题

连接权限问题&#xff1a;手机开启了严格的权限管理机制&#xff0c;若未授予鸿蒙设备连接所需的权限&#xff0c;如蓝牙连接时未开启蓝牙权限&#xff0c;或者 USB 连接时未允许设备进行调试、文件传输等操作&#xff0c;就会导致连接失败。例如&#xff0c;当使用鸿蒙平板通过…

VMware各个软件的作用

VMware作为全球领先的虚拟化与云计算解决方案提供商&#xff0c;其软件产品覆盖了从桌面级虚拟化到企业级云平台的全场景需求。以下结合其核心产品体系&#xff0c;详细解析各软件的功能定位与业务价值&#xff1a; 一、基础虚拟化平台 VMware vSphere 作为企业级服务器虚拟化…

第16届蓝桥杯模拟赛3 python组个人题解

第16届蓝桥杯模拟赛3 python组 思路和答案不保证正确 1.填空 如果一个数 p 是个质数&#xff0c;同时又是整数 a 的约数&#xff0c;则 p 称为 a 的一个质因数。 请问&#xff0c; 2024 的最大的质因数是多少&#xff1f; 因为是填空题&#xff0c;所以直接枚举2023~2 &am…

SQL笔记#复杂查询

一、视图 1、视图和表 使用试图时会执行SELECT语句并创建一张临时表。视图中保存的是SELECT语句;表中保存的是实际数据。 2、创建视图的方法 CREATE VIEW 视图名称(<视图列名1>,<视图列名2>,……) AS <SELECT语句> CREATE VIEW ProductSum (prod…

深度求索(DeepSeek)的AI革命:NLP、CV与智能应用的技术跃迁

Deepseek官网&#xff1a;DeepSeek 引言&#xff1a;AI技术浪潮中的深度求索 近年来&#xff0c;人工智能技术以指数级速度重塑全球产业格局。在这场技术革命中&#xff0c;深度求索&#xff08;DeepSeek&#xff09;凭借其前沿的算法研究、高效的工程化能力以及对垂直场景的…

203、【数组】NLP分词实现(Python)

题目描述 给定一个词典&#xff0c;比如[“杭州”,“西湖”,“博物馆”,“杭州西湖博物馆”,“我”]​ 对于输入的文本进分词&#xff1a;我在杭州的杭州西湖博物馆玩了一天​ 分词结果处理为如下形式的字符串: 我\W 在 杭州\W 的 杭州西湖博物馆\W 玩了一天​ 对于输入的文本…

在 Vue 3 中,如何缓存和复用动态组件

在 Vue 3 中&#xff0c;如何缓存和复用动态组件&#xff0c;这有助于提高应用的性能&#xff0c;避免组件重复创建和销毁带来的开销。下面详细介绍其使用方法和相关配置。 1. 使用 <KeepAlive> 组件缓存动态组件 基本使用 <KeepAlive> 是 Vue 3 内置的一个组件…

Nginx面试宝典【刷题系列】

文章目录 1、nginx是如何实现高并发的&#xff1f;2、Nginx如何处理HTTP请求&#xff1f;3、使用“反向代理服务器”的优点是什么?4、列举Nginx服务器的最佳用途。5、Nginx服务器上的Master和Worker进程分别是什么?6、什么是C10K问题?7、请陈述stub_status和sub_filter指令的…

excel单、双字节字符转换函数(中英文输入法符号转换)

在Excel中通常使用函数WIDECHAR和ASC来实现单、双字节字符之间的转换。其中 WIDECHAR函数将所有的字符转换为双字节&#xff0c;ASC函数将所有的字符转换为单字节 首先来解释一下单双字节的含义。单字节一般对应英文输入法的输入&#xff0c;如英文字母&#xff0c;英文输入法…

使用大语言模型(Deepseek)构建一个基于 SQL 数据的问答系统

GitHub代码仓库 架构 从高层次来看&#xff0c;这些系统的步骤如下&#xff1a; 将问题转换为SQL查询&#xff1a;模型将用户输入转换为SQL查询。 执行SQL查询&#xff1a;执行查询。 回答问题&#xff1a;模型根据查询结果响应用户输入。 样本数据 下载样本数据&#xf…

2024年国赛高教杯数学建模D题反潜航空深弹命中概率问题解题全过程文档及程序

2024年国赛高教杯数学建模 D题 反潜航空深弹命中概率问题 原题再现 应用深水炸弹&#xff08;简称深弹&#xff09;反潜&#xff0c;曾是二战时期反潜的重要手段&#xff0c;而随着现代军事技术的发展&#xff0c;鱼雷已成为现代反潜作战的主要武器。但是&#xff0c;在海峡或…

从0开始学算法-01时间复杂度、异或运算(常见面试题)、对数器的使用

一.时间复杂度 二.异或运算 3&#xff09;不用额外变量交换两个数&#xff1a; //交换a与b的值&#xff0c; 假设a甲&#xff0c;b乙 aa^b; //a甲^乙&#xff0c;b乙 ba^b; //a甲^乙&#xff0c;b甲^乙^乙甲 aa^b; //a甲^乙^甲乙&#xff0c;b甲 &#xff08;能用以上方法交换…

【亲测有效】百度Ueditor富文本编辑器添加插入视频、视频不显示、和插入视频后二次编辑视频标签不显示,显示成img标签,二次保存视频被替换问题,解决方案

【亲测有效】项目使用百度Ueditor富文本编辑器上传视频相关操作问题 1.百度Ueditor富文本编辑器添加插入视频、视频不显示 2.百度Ueditor富文本编辑器插入视频后二次编辑视频标签不显示&#xff0c;在编辑器内显示成img标签&#xff0c;二次保存视频被替换问题 问题1&#xff1…

nginx 正向代理与反向代理

1. 正向代理&#xff08;Forward Proxy&#xff09; 正向代理是指 代理客户端 访问目标服务器&#xff0c;通常用于访问受限资源或隐藏客户端 IP。 工作原理 客户端请求代理服务器&#xff08;如 nginx&#xff09;。代理服务器代表客户端向目标网站发起请求。目标网站返回内…

百度觉醒,李彦宏渴望光荣

文 | 大力财经 作者 | 魏力 2025年刚刚开年&#xff0c;被一家名为DeepSeek的初创公司强势改写。在量化交易出身的创始人梁文锋的带领下&#xff0c;这支团队以不到ChatGPT 6%的训练成本&#xff0c;成功推出了性能可与OpenAI媲美的开源大模型。 此成果一经问世&#xff0c;…

滑动验证组件-微信小程序

微信小程序-滑动验证组件&#xff0c;直接引用就可以了&#xff0c;效果如下&#xff1a; 组件参数&#xff1a; 1.enable-close&#xff1a;是否允许关闭&#xff0c;默认true 2.bind:onsuccess&#xff1a;验证后回调方法 引用方式&#xff1a; <verification wx:if&qu…

Android 实现 RTMP 推流:快速集成指南

简介 在 Android 设备上实现 RTMP 推流,可以用于直播、远程监控等应用场景。本文将基于 rtmp-rtsp-stream-client-java 库,介绍如何在 Android 端快速集成 RTMP 推流,包括权限管理、相机预览、推流控制等关键步骤。 步骤 1. 配置 Maven 仓库 在 settings.gradle.kts 中添…

2024年国赛高教杯数学建模A题板凳龙闹元宵解题全过程文档及程序

2024年国赛高教杯数学建模 A题 板凳龙闹元宵 原题再现 “板凳龙”&#xff0c;又称“盘龙”&#xff0c;是浙闽地区的传统地方民俗文化活动。人们将少则几十条&#xff0c;多则上百条的板凳首尾相连&#xff0c;形成蜿蜒曲折的板凳龙。盘龙时&#xff0c;龙头在前领头&#x…

大连本地知识库的搭建--数据收集与预处理_01

1.马蜂窝爬虫 编程语言&#xff1a;Python爬虫框架&#xff1a;Selenium&#xff08;用于浏览器自动化&#xff09;解析库&#xff1a;BeautifulSoup&#xff08;用于解析HTML&#xff09; 2.爬虫策略 目标网站&#xff1a;马蜂窝&#xff08;https://www.mafengwo.cn/&…