数据结构(二叉树-1)

文章目录

一、树

  1.1 树的概念与结构

  1.2 树的相关术语

  1.3 树的表示

二、二叉树

  2.1 二叉树的概念与结构

  2.2特殊的二叉树

    满二叉树

    完全二叉树

  2.3 二叉树的存储结构

三、实现顺序结构二叉树

  3.1 堆的概念与结构

  3.2 堆的实现

  Heap.h

  Heap.c

    默认初始化堆

    堆的销毁

    堆的插入

  删除堆顶数据


一、树

1.1 树的概念与结构

  • 树是⼀种⾮线性的数据结构,它是由 nn>=0) 个有限结点组成⼀个具有层次关系的集合。把它叫做 树是因为它看起来像⼀棵倒挂的树,也就是说它是根朝上,⽽叶朝下的。
  • 有⼀个特殊的结点,称为根结点,根结点没有前驱结点。
  • 除根结点外,其余结点被分成 M(M>0) 个互不相交的集合 T1T2……Tm ,其中每⼀个集合 Ti(1 <= i <= m) ⼜是⼀棵结构与树类似的⼦树。每棵⼦树的根结点有且只有⼀个前驱,可以0 个或多个后继。因此,树是递归定义的。

 树形结构中,⼦树之间不能有交集,否则就不是树形结构

  •  ⼦树是不相交的(如果存在相交就是图了,图以后得课程会有讲解)
  • 除了根结点外,每个结点有且仅有⼀个⽗结点
  • ⼀棵N个结点的树有N-1条边

1.2 树的相关术语

  •  ⽗结点/双亲结点:若⼀个结点含有⼦结点,则这个结点称为其⼦结点的⽗结点; 如上图:A是B的⽗结点
  • ⼦结点/孩⼦结点:⼀个结点含有的⼦树的根结点称为该结点的⼦结点; 如上图:B是A的孩⼦结点
  • 结点的度:⼀个结点有⼏个孩⼦,他的度就是多少;⽐如A的度为6,F的度为2,K的度为0
  • 树的度:⼀棵树中,最⼤的结点的度称为树的度; 如上图:树的度为 6
  • 叶⼦结点/终端结点:度为 0 的结点称为叶结点; 如上图: BCHI... 等结点为叶结点
  • 分⽀结点/⾮终端结点:度不为 0 的结点; 如上图: DEFG... 等结点为分⽀结点
  • 兄弟结点:具有相同⽗结点的结点互称为兄弟结点(亲兄弟); 如上图: BC 是兄弟结点结点的层次:从根开始定义起,根为第 1 层,根的⼦结点为第 2 层,以此类推;
  • 树的⾼度或深度:树中结点的最⼤层次; 如上图:树的⾼度为 4
  • 结点的祖先:从根到该结点所经分⽀上的所有结点;如上图: A 是所有结点的祖先
  • 路径:⼀条从树中任意节点出发,沿⽗节点-⼦节点连接,达到任意节点的序列;⽐如A到Q的路径为:A-E-J-Q;H到Q的路径H-D-A-E-J-Q
  • ⼦孙:以某结点为根的⼦树中任⼀结点都称为该结点的⼦孙。如上图:所有结点都是A的⼦孙
  • 森林:由 mm>0) 棵互不相交的树的集合称为森林;

1.3 树的表示

  孩⼦兄弟表⽰法:

struct TreeNode{struct Node* child; // 左边开始的第⼀个孩⼦结点struct Node* brother; // 指向其右边的下⼀个兄弟结点int data; // 结点中的数据域};

二、二叉树 

2.1 二叉树的概念与结构

在树形结构中,我们最常⽤的就是⼆叉树,⼀棵⼆叉树是结点的⼀个有限集合,该集合由⼀个根结点加上两棵别称为左⼦树和右⼦树的⼆叉树组成或者为空。  

从上图可以看出⼆叉树具备以下特点:
  1.  ⼆叉树不存在度⼤于 2 的结点
  2.  ⼆叉树的⼦树有左右之分,次序不能颠倒,因此⼆叉树是有序树
注意:对于任意的⼆叉树都是由以下⼏种情况复合⽽成的:

2.2特殊的二叉树

满二叉树

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

完全二叉树

 完全⼆叉树是效率很⾼的数据结构,完全⼆叉树是由满⼆叉树⽽引出来的。对于深度为 K 的,有 n 个结点的⼆叉树,当且仅当其每⼀个结点都与深度为K的满⼆叉树中编号从 1 n 的结点⼀⼀对应时称之为完全⼆叉树。要注意的是满⼆叉树是⼀种特殊的完全⼆叉树。

(假设二叉树层次为 k ,除了第 k 层外,每层结点的个数达到最大结点数,第 k 层结点个数不一定达到最大结点数)

⼆叉树性质
根据满⼆叉树的特点可知:
1)若规定根结点的层数为 1 ,则⼀棵⾮空⼆叉树的第i层上最多有 2 i −1 个结点
2)若规定根结点的层数为 1 ,则深度为 h 的⼆叉树的最⼤结点数是 2 h − 1 3)若规定根结点的层数为 1 ,具有 n 个结点的满⼆叉树的深度 ( log
以2为底, n+1 为对数)

 2.3 二叉树的存储结构

⼆叉树⼀般可以使⽤两种结构存储,⼀种顺序结构,⼀种链式结构。
下面我们先来使用顺序结构实现二叉树。

  • 顺序结构存储就是使⽤数组来存储,⼀般使⽤数组只适合表⽰完全⼆叉树,因为不是完全⼆叉树会有空间的浪费,完全⼆叉树更适合使⽤顺序结构存储。

现实中我们通常把堆(⼀种⼆叉树)使⽤顺序结构的数组来存储,需要注意的是这⾥的堆和操作系统虚拟进程地址空间中的堆是两回事,⼀个是数据结构,⼀个是操作系统中管理内存的⼀块区域分段。

三、实现顺序结构二叉树

⼀般堆使用顺序结构的数组来存储数据,堆是⼀种特殊的⼆叉树,具有⼆叉树的特性的同时,还具备其他的特性。

3.1 堆的概念与结构

如果有⼀个关键码的集合 ,把它的所有元素按完全⼆叉树的顺序存储⽅式存储,在⼀个⼀维数组中,并满⾜: ( 且 ), i = 0、1 2... ,则称为⼩堆(或⼤堆)。将根结点最⼤的堆叫做最⼤堆或⼤根堆,根结点最⼩的堆叫做最⼩堆或⼩根堆。

小根堆                                                        大根堆

  • 堆中某个结点的值总是不⼤于或不⼩于其⽗结点的值;
  • 堆总是⼀棵完全⼆叉树。
⼆叉树性质
  • 对于具有 n 个结点的完全⼆叉树,如果按照从上⾄下从左⾄右的数组顺序对所有结点从0 开始编号,则对于序号为 i 的结点有:
  1. i>0 i 位置结点的双亲序号: (i-1)/2 i=0 i 为根结点编号,⽆双亲结点
  2. 若 2i+1<n ,左孩⼦序号: 2i+1 2i+1>=n 否则⽆左孩⼦
  3. 2i+2<n ,右孩⼦序号: 2i+2 2i+2>=n 否则⽆右孩⼦

 3.2 堆的实现

以小根堆为例子:

Heap.h

#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>//定义堆的结构---数组typedef int HPDataType;typedef struct Heap
{HPDataType* arr;int size;//有效的数据个数int capacity;//空间大小
}HP;//初始化
void HPInit(HP* php);//销毁
void HPDestroy(HP* php);//堆的插入
void HPPush(HP* php, HPDataType x);//出堆,删除堆顶数据
void HPPop(HP* php);//返回堆顶数据
HPDataType HPTop(HP* php);// 判空
bool HPEmpty(HP* php);

Heap.c

默认初始化堆
void HPInit(HP* php)
{assert(php);php->arr = NULL;php->capacity = php->size = 0;
}

堆的销毁
void HPDestroy(HP* php)
{assert(php);if (php->arr){free(php->arr);php->arr = NULL;php->capacity = php->size - 0;}
}
堆的插入

    如果要在下一个数据 “50” 到 arr【6】的位置上就不满足小堆的特性,

此时我们就要用到:堆的向上调整算法

向上调整算法
先将元素插⼊到堆的末尾,即最后⼀个孩⼦之后
插⼊之后如果堆的性质遭到破坏,将新插⼊结点顺着其双双亲往上调整到合适位置即可

void swap(int* x, int* y)
{int z = *x;*x = *y;*y = z;
}void Adjustup(HPDataType* arr, int child)
{int parent = (child - 1) / 2;while (child > 0){if (arr[child] < arr[parent])             //如果插入的数据大小小于他的父节点{swap(&arr[child], &arr[parent]);      //交换child = parent;                       //交换后的孩结点来到原来他的父节点的位置  parent = 2 * child - 1;}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->arr, newcapacity * sizeof(HPDataType));if (tmp  == NULL){perror("realloc fail!");exit(1);}php->arr = tmp;php->capacity = newcapacity;}php->arr[php->size] = x;php->size++;Adjustup(php->arr, php->size - 1);
}

 

 删除堆顶数据

    如果直接删除 arr【0】,就会改变原先堆的结构,所以我么可以先先将头和尾的数据交换,在删除 arr【5】,但是又有问题出现。交换删除后的数据有可能不满足小堆的特性,此时就要用到:堆的向下调整算法 

向下调整算法
将堆顶元素与堆中最后⼀个元素进⾏交换
删除堆中最后⼀个元素  
将堆顶元素向下调整到满⾜堆特性为⽌

void AdjustDown(HPDataType* arr, int parent, int n)
{int child = parent * 2 + 1;  //左孩子while (child < n)     //这里注意循环的条件{//找左右孩子中找最小的if (child + 1 < n && arr[child] > arr[child + 1]){child++;}if (arr[child] < arr[parent]){swap(&arr[child], &arr[parent]);parent = child;child = parent * 2 + 1;}else{break;}}
}void HPPop(HP* php)
{assert(php && php->size);//arr[0]         arr[size-1]swap(&php->arr[0], &php->arr[php->size - 1]);php->size--;AdjustDown(php->arr, 0, php->size);}

test.c

最后测试一下代码的实现

#include"Heap.h"void Hptest()
{HP hp;HPInit(&hp);int arr[] = { 17,25,60,54,30,70 };for (int i = 0; i < 6; i++){HPPush(&hp, arr[i]);}HPPop(&hp);
}int main()
{Hptest();return 0;
}

3.3 堆的应用

堆排序 

方法一:基于已有数组建堆、取堆顶元素完成排序版本

// 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);
}

方法二:

// 升序,建⼤堆
// 降序,建⼩堆
// 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;}}

未完待续~ 

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

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

相关文章

Python--Pandas基础------1

Pandas 是一个基于 Python 编程语言的开源数据分析工具&#xff0c;专注于提供快速、灵活且高效的数据结构和数据操作工具。Pandas 提供了丰富的功能&#xff0c;包括数据清洗、数据转换、数据分组、数据合并等。它能够轻松处理各种数据源的数据导入和导出&#xff0c;如CSV、E…

2024100读书笔记|《飞花令·夏》——鲜鲫银丝脍,香芹碧涧羹,人皆苦炎热,我爱夏日长

2024100读书笔记|《飞花令夏》——鲜鲫银丝脍&#xff0c;香芹碧涧羹&#xff0c;人皆苦炎热&#xff0c;我爱夏日长 《飞花令夏&#xff08;中国文化古典诗词品鉴&#xff09;》素心落雪 编著&#xff0c;飞花令得名于唐代诗人韩翃《寒食》中的名句“春城无处不飞花”&#xf…

matlab仿真 模拟调制(下)

&#xff08;内容源自详解MATLAB&#xff0f;SIMULINK 通信系统建模与仿真 刘学勇编著第五章内容&#xff0c;有兴趣的读者请阅读原书&#xff09; clear all ts0.001; t0:ts:10-ts; fs1/ts; dffs/length(t); msgrandi([-3 3],100,1); msg1msg*ones(1,fs/10); msg2reshape(ms…

Stable Diffusion 使用详解(1)---- 提示词及相关参数

目录 背景 提示词 内容提示词 人物及主体特征 场景 环境光照 画幅视角 注意事项及示例 标准化提示词 画质等级 风格与真实性 具体要求 背景处理 光线与色彩 负向提示词 小结 常用工具 另外几个相关参数 迭代步数 宽度与高度 提示词引导系数 图片数量 背景…

算法学习7——回溯算法

什么是回溯算法&#xff1f; 回溯算法是一种试探性搜索算法&#xff0c;通过递归的方式逐步构建解决方案&#xff0c;并在发现当前路径不满足条件时回退到上一步。回溯算法特别适用于组合优化问题&#xff0c;如全排列、组合、子集和图的着色问题等。 回溯算法的特点 递归&a…

cdh社区版免费替代方案。

免费的话&#xff0c;现在国产化的东西其实也还可以&#xff0c;而且国家在追求信创&#xff08;信息科技创新&#xff09;嘛。只有用的人多了&#xff0c;用的公司多了&#xff0c;国产的才有钱。才会发展的更好&#xff0c;良性循环。恶性的就是操作系统&#xff0c;大家都在…

Unity | Shader基础知识(第十九集:顶点着色器的进一步理解-易错点讲解)

目录 一、前言 二、网格 三、方法UnityObjectToClipPos 四、顶点着色器和片元着色器的POSITION 五、作者的碎碎念 一、前言 之前我们简单讲解过顶点着色器&#xff0c;也简单讲解了表面着色器&#xff0c;并且一起做了一些案例&#xff0c;因为顶点着色器本身是更自由一些…

RT-Thread必考面试题及参考答案

目录 RT-Thread操作系统的核心架构是什么? RT-Thread支持哪些微处理器架构? RT-Thread中任务调度的基本原则是什么? 如何在RT-Thread中创建一个新的线程? RT-Thread中的线程优先级如何影响调度? RT-Thread中的信号量和互斥锁有何区别? 描述一下RT-Thread中消息队列…

【Git多人协作开发】不同的分支下的多人协作开发模式

目录 0.前言背景 1.开发者1☞完成准备工作&协作开发 1.1查看分支情况 1.2创建本地分支feature-1 1.3三板斧 1.4push推本地分支feature-1到远程仓库 2.开发者2☞完成准备工作&协作开发 2.1创建本地分支feature-2 2.2三板斧 2.2push推送本地feature-2到远程仓库…

Sprong Boot学习|使用 guava-retrying 实现重试

背景 后端业务系统可能会在接口调用失败、网络拥塞超时、任务执行失败、系统错误等异常情况出现的时候进行重试操作&#xff0c;然而不同的场景对于重试的延迟间隔&#xff0c;频次等会有不同的要求&#xff0c;如果自己编排重试代码会比较繁琐&#xff0c;使用 guava-retryin…

LeetCode:合并2个有序数组(C语言)

1、2个非递减排序的整数数组nums1和nums2&#xff0c;2个整数m和n&#xff0c;代表nums1和nums2中的元素个数。合并nums2到nums1&#xff0c;合并后的数组也进行非递减排序 2、示例 示例 1&#xff1a; 输入&#xff1a;nums1 [1,2,3,0,0,0], m 3, nums2 [2,5,6], n 3 输出…

springSecurity学习之springSecurity web如何取得用户信息

web如何取得用户信息 之前说过SecurityContextHolder默认使用的是ThreadLocal来进行存储的&#xff0c;而且每次都会清除&#xff0c;但是web每次请求都会验证用户权限&#xff0c;这是如何做到的呢&#xff1f; 这是通过SecurityContextPersistenceFilter来实现的&#xff0…

FineBI连接MySQL5.7

一、在FineBI系统管理中&#xff0c;点击【新建数据库连接】 选择MySQL数据库 配置数据库连接&#xff0c;如下&#xff0c;其中数据库名称就是需要连接的目标数据库

《昇思 25 天学习打卡营第 21 天 | LSTM+CRF序列标注模型实现 》

《昇思 25 天学习打卡营第 21 天 | LSTMCRF序列标注模型实现 》 活动地址&#xff1a;https://xihe.mindspore.cn/events/mindspore-training-camp 签名&#xff1a;Sam9029 序列标注问题概述 序列标注是信息抽取中的一个关键任务&#xff0c;包括分词、词性标注、命名实体识别…

【通信协议-RTCM】MSM语句(2) - RINEXMSM7语句总结(重要!自动化开发计算卫星状态常用)

注释&#xff1a; 在工作中主要负责的是RTCM-MSM7语句相关开发工作&#xff0c;所以主要介绍的就是MSM7语句相关内容 1. 相位校准参考信号 2. MSM1、MSM2、MSM3、MSM4、MSM5、MSM6和MSM7的消息头内容 DATA FIELDDF NUMBERDATA TYPENO. OF BITSNOTES Message Number - 消息编…

四、Object 通⽤⽅法

Object是Java中所有类的基类&#xff0c;是最顶级的父类。在Java中&#xff0c;每个类都直接或间接地继承自Object类&#xff0c;即使没有显式地声明继承关系&#xff0c;Java也会自动为每个类添加extends Object。这意味着&#xff0c;Object类中定义的方法可以被所有Java类使…

React组件定义

一、定义 组件是是构建用户界面&#xff08;UI&#xff09;的基础&#xff0c;它可以是一个输入框、按钮、也可以是一整个页面。组件可以分为以下2种类型&#xff1a; 1、函数组件&#xff08;Functional Components&#xff09; 顾名思义就是用来函数定义的组件&#xff0c…

DML数据操作语句和基本的DQL语句

一、MySQL对数据的增删改查 1.DML语句 1.1 增加数据(INSERT) insert into 表名 (字段名,字段名,...字段名) values/value (值,值,...值) 1.1.1 新增数据的具体实现 &#xff08;1&#xff09;全字段的插入 方式一&#xff1a; insert into student (sid,sname,birthday,ssex,…

C++的智能指针

说实话以前用这个很少&#xff0c;一个指针打天下&#xff0c;不过都智能了&#xff0c;分配了就不管了&#xff0c;想来还是很方便。。。 1 unique_ptr 代码示例&#xff1a; #include <iostream> #include <memory>class MyClass { public:MyClass() { std::c…

【2024最新华为OD-C/D卷试题汇总】[支持在线评测] 开源项目热度排行榜(100分) - 三语言AC题解(Python/Java/Cpp)

🍭 大家好这里是清隆Coding ,一枚热爱算法的程序员 ✨ 本系列打算持续跟新华为OD-C/D卷的三语言AC题解 👏 感谢大家的订阅➕ 和 喜欢💗 🍿 最新华为OD机试D卷目录,全、新、准,题目覆盖率达 95% 以上,支持题目在线评测,专栏文章质量平均 93 分 最新华为OD机试目录…