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

树及其遍历

文章目录

    • 树定义
    • 专业术语
    • 树分类
  • 二叉树
    • 分类
    • 存储
      • 连续存储(完全二叉树)
      • 链式存储
      • 一般树的存储
      • 森林的存储
    • 线索二叉树
    • 哈夫曼树
      • 构造步骤
    • 遍历
      • 先序遍历
      • 中序遍历
      • 后续遍历
    • 链式二叉树遍历具体代码
    • 已知两种遍历序列求原始二叉树
      • 已知先序和中序求后序
      • 已知中序和后序求先序
      • 已知先序和后序求中序
  • 树的应用

树定义

像这种有层次关系进行存储的,就是一棵树,是非线性结构。
在这里插入图片描述
以递归的方式进行定义。

专业定义:

  • 有且只有一个称为根的节点。
  • 有若干个互不相交的子树,这些子树本身也是一棵树。

通俗定义:

  • 树是由节点和边组成。
  • 每一个节点节点只有一个父节点但可以有多个子节点。
  • 有一个节点例外,该节点没有父节点,此节点称为根节点。

专业术语

  • 节点:就是一个个的圈。
  • 父节点:和当前节点上一个紧挨着的节点。
  • 子节点:父节点下连着的子节点。
  • 子孙:父节点下的所有节点。
  • 深度:从根节点到最底层的层数称为深度。
  • 叶子节点:没有子节点的节点。
  • 非终端节点:实际上就是非叶子节点,有子节点的节点。
  • 根节点:看有没有子节点。
  • 度:子节点的个数称为度。

树分类

  • 一般树:任意一个节点的子节点的个数都不受限制
  • 二叉树:任意一个节点的子节点个数最多两个,且子节点的位置不可更改。
  • 森林:有互不相交的,一般的树合在一起,就是森林。

二叉树

分类

  • 一般二叉树
  • 满二叉树:在不增加树的层数的前提下,无法再多添加一个节点的二叉树就是满二叉树。
  • 完全二叉树:如果只是删除了满二叉树最底层最右边的连续若干个节点,这样形成的二叉树就是完全的二叉树。
    满二叉树是完全二叉树的一个特例。

存储

连续存储(完全二叉树)

要把一颗一般的二叉树以数组方式存储的话,必须先把这个一般的二叉树转化为完全二叉树。

eg:
在这里插入图片描述
首先这不是一个完全二叉树,因为完全二叉树先是一个满的二叉树,后来再在最底一层砍。所以要使用连续存储就必须先把这个二叉树变成完全二叉树。

在这里插入图片描述
先变成满二叉树,再把最底层的最右边得到删掉,就成了完全二叉树。
在这里插入图片描述
黄色线框的可以不保存。(先转化成满二叉树,再把最后一层最右边开始的点删掉,就是完全二叉树)红色的是有效节点,别人是无法通过零散的红色有效节点还原二叉树的本来面目的。(排序通过先中后进行排序。)
树是非线性的,将非线性的数转换成线性结构的,结果是不知道的。
数组只能以完全二叉树的方式进行存储,即不能只存放有效节点,因为通过先中后进行排序后,还原不了其本来的面目。所以把所有点都存进去,才好还原。

优点:查找某个节点的父节点和子节点很快。
缺点:耗用内存空间过大。

链式存储

通过指针域弄成一个连续的存储。

一般树的存储

  1. 双亲表示法:求父节点很方便,因为跟的是下标。
  2. 孩子表示法:求子节点方便,跟着的是子节点。
  3. 双亲孩子表示法:有链表,有数组,有下标,指针域,求父节点与子节点都很方便,就是代码复杂。
  4. 二叉树表示法:把一个普通树转化成二叉树来存储,具体转换方法是,设法保证任意一个节点左指针域指向它的第一个孩子,右指针域指向它的下一个兄弟节点,只要能满足此条件,就能把一个普通的数转化为二叉树。(转化时,只有左边的孩子,右边都是与孩子并列的兄弟,即一个普通的数转化为二叉树就没有右子树。例如下方的2,3,4,5,真正是孩子的只有2,然后3,4,5都是与其并列的项,排在右边。3也没有左兄弟,所以把4排在右边,5就同理了。)
    eg如下,将一个普通的树转化为二叉树。
    在这里插入图片描述

森林的存储

几个树互不相交,就组成了一个森林。
在这里插入图片描述
先把森林转化为一个二叉树,再进行存储。而森林的二叉树存储规则为:把B当A的兄弟,把G当B的兄弟。
在这里插入图片描述
森林转成二叉树的步骤与之前一般树转化为二叉树也是一致的。

线索二叉树

当用二叉链表作为二叉树的存储结构时,可以很方便地找到某个结点的左右孩子;但一般情况下,无法直接找到该结点在某种遍历序列中的前驱和后继结点。
在这里插入图片描述
因为还剩下了n+1个指针域,将其利用起来,存储前驱后继指针的地址,称此为线索。
在这里插入图片描述
在这里插入图片描述
可以用ltag与rtag的方式来区分是否为孩子还是线索。(左孩子与前驱,右孩子与后继)

//线索二叉树的结点结构
typedef struct BiThrNode{int data;int ltag, rtag;struct BiThrNode *lchild, rchild;
}BiThrNode, *BiThrTree;

在这里插入图片描述
在这里插入图片描述
因为首尾还有两个指针域悬空,可以增加一个头结点,让其指向头结点。
在这里插入图片描述

哈夫曼树

在这里插入图片描述
相当于把一个带权重的树进行重排,排成一个考虑权重最优的二叉树。

构造步骤

在这里插入图片描述
在这里插入图片描述
两个权重相同的直接连接,权重不相同的按照权重小的为左孩子,权重大的为右孩子的原则,进行排列。

遍历

把非线性的树转化成非线性的序列。

先序遍历

先访问根节点,再先序访问左子树,再先序访问右子树。假设二叉树如下:
在这里插入图片描述

运用递归的思想,先访问根节点A,再先序访问左子树,再先序访问右子树。在访问左子树的时候,因为左子树也是一棵树,所以会又绕到了先访问根节点B,再顺着来看左子树与右子树,即B的左子树为D,B没有右子树,因为D没有左子树以及右子树,为空,则此次递归结束,BD访问完毕;紧接着先序遍历A的右子树,右子树是个二叉树,再从根节点开始,再遍历左子树,再遍历右子树。都访问完毕之后,才是访问完毕。
eg:
在这里插入图片描述
最后的遍历节点就是ABCDEFLQMNS。

中序遍历

中序遍历左子树,再访问根节点,再中序遍历右子树。
在这里插入图片描述
先中序遍历左子树,B的左子树为空,所以先访问左子树的根节点,即为B,所以先B,B访问完访问B的右子树,也是非空的,所以递归思想,B的右子树先去中序遍历左子树,B的左子树为C的左子树,所以先访问D,再访问根节点C,再访问E。
最后顺序为BDCEALFNQM

eg:
在这里插入图片描述

遍历顺序:BDCAMQELN

后续遍历

中序遍历左子树,中序遍历右子树,再访问根节点。遍历都是以根节点的顺序来判断的。
eg:
在这里插入图片描述

遍历顺序:BDMFLECA(先全部的左,再全部的右,最后根)

在这里插入图片描述

遍历顺序:NWTSFPLQM

链式二叉树遍历具体代码

# include <stdio.h>
# include <malloc.h>struct BTNode
{char data;struct BTNode * pLchild; struct BTNode * pRchild;
};void PostTraverseBTree(struct BTNode * pT);
struct BTNode * CreateBTree(void);
void PreTraverseBTree(struct BTNode * pT);
void InTraverseBTree(struct BTNode * pT);int main(void)
{struct BTNode * pT = CreateBTree();//	PreTraverseBTree(pT);
//	InTraverseBTree(pT);PostTraverseBTree(pT);return 0;
}void PostTraverseBTree(struct BTNode * pT)
{if (NULL != pT){if (NULL != pT->pLchild){PostTraverseBTree(pT->pLchild);}	if (NULL != pT->pRchild){PostTraverseBTree(pT->pRchild);}printf("%c\n", pT->data);}
}void InTraverseBTree(struct BTNode * pT)
{if (NULL != pT){if (NULL != pT->pLchild){InTraverseBTree(pT->pLchild);}printf("%c\n", pT->data);if (NULL != pT->pRchild){InTraverseBTree(pT->pRchild);}	}
}void PreTraverseBTree(struct BTNode * pT)
{if (NULL != pT){printf("%c\n", pT->data);if (NULL != pT->pLchild){PreTraverseBTree(pT->pLchild);}if (NULL != pT->pRchild){PreTraverseBTree(pT->pRchild);}	}	
}struct BTNode * CreateBTree(void)
{struct BTNode * pA = (struct BTNode *)malloc(sizeof(struct BTNode));struct BTNode * pB = (struct BTNode *)malloc(sizeof(struct BTNode));struct BTNode * pC = (struct BTNode *)malloc(sizeof(struct BTNode));struct BTNode * pD = (struct BTNode *)malloc(sizeof(struct BTNode));struct BTNode * pE = (struct BTNode *)malloc(sizeof(struct BTNode));pA->data = 'A';pB->data = 'B';pC->data = 'C';pD->data = 'D';pE->data = 'E';pA->pLchild = pB;pA->pRchild = pC;pB->pLchild = pB->pRchild = NULL;pC->pLchild = pD;pC->pRchild = NULL;pD->pLchild = NULL;pD->pRchild = pE;pE->pLchild = pE->pRchild = NULL;return pA;
}

已知两种遍历序列求原始二叉树

单纯的知道先中后三种序列当中的任何一个,都不能把原始的二叉树序列还原回来,当已知两种序列,可以推出原始的二叉树。

已知先序和中序求后序

示例1:
先序:ABCDEFGH
中序:BDCEAFHG
求后序:因为根据先序,第一个访问的一定是根节点,所以根节点为A,再中序,中间的A确定是根节点,A旁边的是左子树,A右边的是右子树。确定了左子树BDCE与右子树FHG,现在分别找左右子树的根节点,由先序序列可知,先出现的肯定为根。之后确定根节点为BF,之后确定下一个根节点为C,因为中序先遍历左子树,所以D是C的左子树,E就是C的右子树,至此,A的左子树全部推完。右子树类似,推完F,发现在中序序列当中F左边没有点了,说明F没有左子树,只有右子树G,G的左边有H,所以H是G的左子树。
所以后序序列就是DECBHGFA
在这里插入图片描述
示例2:
先序:ABDGHCEFI
中序:GDHBAECIF
求后序:根节点为A,A的左子树为GDHB,右子树为ECIF,左子树当中,第一个根节点为B,B的左子树为GDH,D又为根节点,所以GH为其两树,G为左子树,H为右子树,至此A的左子树完全推出;A的右子树为ECIF,在ECIF当中,C为根节点,C的左子树为E,C的右子树为F,F的左子树为I,至此,A的右子树完全推出。
在这里插入图片描述
后序即为:GHDBIEFCA

已知中序和后序求先序

中序:BDCEAFHG
后序:DECBHGFA
求先序:根节点为A,最后出现的后序节点是根节点。所以BDCE是左子树,FHG是右子树。F是根节点,B也是根节点,因为在各个组合中最后出现(依照后序)再在中序中查找,B没有左子树,只有右子树DCE,C在后序最后出现,是根(哪一个在后序最后出现,哪一个就是根),所以C又有左子树又有右子树,左子树为D,右子树为E,至此A的左子树全部推完;A的右子树是FHG,F是根节点,F只有右子树HG,根节点为G,G有左子树H,至此,A的右子树全部推完。
在这里插入图片描述
先序:ABCDEFGH

已知先序和后序求中序

和以上两种情况类似。

树的应用

  • 树是数据库中数据组织的一种重要形式
  • OS当中的子父进程的关系也是树
  • 面向对象语言中类的继承关系
  • 哈夫曼树
  • B树
  • B+树
  • B*树
  • 红黑树
  • AVL树

相关文章:

树及其遍历

文章目录 树树定义专业术语树分类 二叉树分类存储连续存储&#xff08;完全二叉树&#xff09;链式存储一般树的存储森林的存储 线索二叉树哈夫曼树构造步骤 遍历先序遍历中序遍历后续遍历 链式二叉树遍历具体代码已知两种遍历序列求原始二叉树已知先序和中序求后序已知中序和后…...

Qt报错解决办法

anaconda环境安装qt报错解决办法 报错&#xff1a;thresholdGap: 20 pointsShape: 164142 qt.qpa.plugin: Could not find the Qt platform plugin “wayland” in “/home/tianhailong/anaconda3/envs/edge_algorithm/lib/python3.8/site-packages/cv2/qt/plugins” This app…...

Python(四十七)列表对象的创建

❤️ 专栏简介&#xff1a;本专栏记录了我个人从零开始学习Python编程的过程。在这个专栏中&#xff0c;我将分享我在学习Python的过程中的学习笔记、学习路线以及各个知识点。 ☀️ 专栏适用人群 &#xff1a;本专栏适用于希望学习Python编程的初学者和有一定编程基础的人。无…...

#systemverilog# 说说Systemverilog中《automatic》那些事儿

前面我们学习了有关systemverilog语言中有关《static》的一些知识,同static 关系比较好的哥们,那就是 《automatic》。今天,我们了解认识一下。 在systemveriog中,存在三种并发执行语句,分别是fork..join,fork...join_any和fork..join_none,其中只有fork...join_none不…...

C/C++ 动态内存分配与它的指针变量

一、什么是内存的动态分配 全局变量分配在内存中的静态存储区。局部变量&#xff08;包括形参&#xff09;分配在内存中的动态存储区&#xff0c;这个存储区是一个称为栈的区域。除此之外&#xff0c;C语言还允许建立内存动态分配区域&#xff0c;以存放一些临时用的数据&…...

UE5初学者快速入门教程

虚幻引擎是一系列游戏开发工具&#xff0c;能够将 2D 手机游戏制作为 AAA 游戏机游戏。虚幻引擎 5 用于开发下一代游戏&#xff0c;包括Senuas Saga: Hellblade 2、Redfall&#xff08;来自 Arkane Austin 的合作射击游戏&#xff09;、Dragon Quest XII: The Flames of Fate、…...

论文笔记--FEDERATED LEARNING: STRATEGIES FOR IMPROVING COMMUNICATION EFFICIENCY

论文笔记--FEDERATED LEARNING: STRATEGIES FOR IMPROVING COMMUNICATION EFFICIENCY 1. 文章简介2. 文章概括3 文章重点技术3.1 联邦学习(federated learning, FL)3.2 Structured updates3.3 Sketched Update 4. 文章亮点5. 原文传送门 1. 文章简介 标题&#xff1a;FEDERATE…...

STM32MP157驱动开发——按键驱动(异步通知)

文章目录 “异步通知 ”机制&#xff1a;信号的宏定义&#xff1a;信号注册 APP执行过程驱动编程做的事应用编程做的事异步通知方式的按键驱动程序(stm32mp157)button_test.cgpio_key_drv.cMakefile修改设备树文件编译测试 “异步通知 ”机制&#xff1a; 信号的宏定义&#x…...

医疗器械维修工程师心得

彩虹医械维修技能班9月将开展本年第三期长期班&#xff0c;目前咨询人员也陆续多了起来&#xff0c;很多刚了解到医疗行业的&#xff0c;自身也没有多少相关的基础&#xff0c;在咨询时会问到没有基础能否学的会&#xff1f; 做了这行业的都知道&#xff0c;无论多么复杂的设备…...

Vue3 Radio单选切换展示不同内容

Vue3 Radio单选框切换展示不同内容 环境&#xff1a;vue3tsviteelement plus 技巧&#xff1a;v-if&#xff0c;v-show的使用 实现功能&#xff1a;点击单选框展示不同的输入框 效果实现前的代码&#xff1a; <template><div class"home"><el-row …...

FreeRTOS之二值信号量

什么是信号量&#xff1f; 信号量&#xff08;Semaphore&#xff09;&#xff0c;是在多任务环境下使用的一种机制&#xff0c;是可以用来保证两个或多个关键代 码段不被并发调用。 信号量这个名字&#xff0c;我们可以把它拆分来看&#xff0c;信号可以起到通知信号的作用&am…...

ChatGPT API进阶调用指南

原文&#xff1a;ChatGPT API进阶调用指南 ChatGPT API 进阶调用指南 ChatGPT API 是基于 OpenAI 的 GPT模型的一个强大工具&#xff0c;可以用于构建各种对话式应用。以下是一些使用 Markdown 语法的进阶调用指南&#xff0c;以帮助您更好地利用 ChatGPT API。 设置用户角色…...

人工智能术语翻译(四)

文章目录 摘要MNOP 摘要 人工智能术语翻译第四部分&#xff0c;包括I、J、K、L开头的词汇&#xff01; M 英文术语中文翻译常用缩写备注Machine Learning Model机器学习模型Machine Learning机器学习ML机器学习Machine Translation机器翻译MTMacro Average宏平均Macro-F1宏…...

kubernetes持久化存储卷

kubernetes持久化存储卷 kubernetes持久化存储卷一、存储卷介绍二、存储卷的分类三、存储卷的选择四、本地存储卷之emptyDir五、本地存储卷之 hostPath六、网络存储卷之nfs七、PV(持久存储卷)与PVC(持久存储卷声明)7.1 认识pv与pvc7.2 pv与pvc之间的关系7.3 实现nfs类型pv与pvc…...

【Rust笔记】意译解构 Object Safety for trait

意译解构Object Safety for trait 借助【虚表vtable】对被调用成员函数【运行时内存寻址】的作法允许系统编程语言Rust模仿出OOP高级计算机语言才具备的【专用多态Ad-hoc Polymorphism】特性。 计算机高级语言中的“多态”术语是一个泛指。它通常可被细化为 基于继承关系的“子…...

Spring Boot单元测试入门指南

Spring Boot单元测试入门指南 JUnit是一个成熟和广泛应用的Java单元测试框架&#xff0c;它提供了丰富的功能和灵活的扩展机制&#xff0c;可以帮助开发人员编写高质量的单元测试。通过JUnit&#xff0c;开发人员可以更加自信地进行重构、维护和改进代码&#xff0c;同时提高代…...

《面试1v1》如何能从Kafka得到准确的信息

&#x1f345; 作者简介&#xff1a;王哥&#xff0c;CSDN2022博客总榜Top100&#x1f3c6;、博客专家&#x1f4aa; &#x1f345; 技术交流&#xff1a;定期更新Java硬核干货&#xff0c;不定期送书活动 &#x1f345; 王哥多年工作总结&#xff1a;Java学习路线总结&#xf…...

2023秋招面试题持续更新中。。。

目录 1.八股文渐进式MVVM三次握手&#xff0c;四次挥手viteajax组件化和模块化虚拟dom原理流程浏览器内核浏览器渲染过程回流和重绘nextTick 2.项目相关1.声明式导航和编程式导航重写push和replace方法&#xff1a;性能优化图片懒加载路由懒加载 http请求方式 1.八股文 渐进式…...

Java | 数组排序算法

一、冒泡排序 冒泡排序的基本思想是对比相邻的元素值&#xff0c;如果满足条件就交换元素值&#xff0c;把较小的元素移到数组前面&#xff0c;把较大的元素移到数组后面&#xff08;也就是交换两个元素的位置&#xff09;&#xff0c;这样较小的元素就像气泡一样从底部升到顶…...

android studio 连接SQLite数据库并实现增删改查功能

功能代码及调试代码 package com.example.bankappdemo;import android.annotation.SuppressLint; import android.content.ContentValues; import android.database.sqlite.SQLiteDatabase; import android.os.Bundle; import android.util.Log; import android.view.View; im…...

跑步适合戴什么样的耳机、最好的跑步耳机推荐

每个人对于运动的方式都不尽相同&#xff0c;但大多数热爱运动的朋友都离不开音乐的陪伴。运动和带有节奏感的音乐能够激发我们更多的热情和动力。特别是在夏日的时候&#xff0c;我非常喜欢跑步。在酷热的天气里&#xff0c;如果没有音乐的伴随&#xff0c;跑步会变得单调乏味…...

物联网的通信协议

物联网的通信协议 目录 物联网的通信协议一、UART串口通信1.1 串口通信1.2 异步收发1.3 波特率1.4 串口通信协议的数据帧1.5 优缺点1.5.1 优点1.5.2 缺点 二、I^2^C2.1 I^2^C2.2 I^2^C2.3 数据有效性2.4 起始条件S和停止条件P2.5 数据格式2.6 协议数据单元PDU2.7 优缺点2.7.1 优…...

【业务功能篇56】SpringBoot 日志SLF4J Logback

3.5.1 日志框架分类与选择 3.5.1.1 日志框架的分类 日志门面 (日志抽象)日志实现JCL(Jakarta Commons Logging) SLF4J(Simple Logging Facade for Java)Jul(Java Util Logging) , Log4j , Log4j2 , Logback 记录型日志框架 Jul (Java Util Logging)&#xff1a;JDK中的日志…...

leetcode 53. 最大子数组和

2023.7.28 要求找最大和的 连续子数组&#xff0c; 我的思路是用一个temp记录局部最优值&#xff0c;用ans记录全局最优值。 然后在每次for循环进行一个判断&#xff1a;当前遍历元素temp值 是否大于当前遍历元素的值&#xff0c;如果大于&#xff0c;说明temp值是帮了正忙的&a…...

js 下载url返回的excel数据,并解析为json

XLSX GitHub地址&#xff1a;https://github.com/SheetJS/sheetjs/blob/github/dist/xlsx.full.min.js 需要先引入&#xff1a;XLSX.full.min.js // 下载文件的请求 fetch(downloadFileUrl).then(response > {return rsp.blob() }).then(data > {let reader new FileR…...

图文教程:使用 Photoshop、3ds Max 和 After Effects 创建被风暴摧毁的小屋

推荐&#xff1a; NSDT场景编辑器助你快速搭建可二次开发的3D应用场景 1. 在 Photoshop 中设置图像 步骤 1 打开 Photoshop。 打开 Photoshop 步骤 2 我已经将小屋的图像导入到Photoshop中以演示 影响。如果您愿意&#xff0c;可以使用其他图像。 图片导入 步骤 3 由于小…...

学习Maven Web 应用

Maven Web 应用 本章节我们将学习如何使用版本控制系统 Maven 来管理一个基于 web 的项目&#xff0c;如何创建、构建、部署已经运行一个 web 应用。 创建 Web 应用 我们可以使用 maven-archetype-webapp 插件来创建一个简单的 Java web 应用。 打开命令控制台&#xff0c;…...

page allocation stalls for 问题调研

一.现象分析和内存管理基本概念介绍 最近有一台linux出现卡死的状态,系统不反应,无法ssh登录,只能通过电源关机重启操作恢复,重启后登录系统后台,拉取kernel日志,如下 Jul 12 18:48:06 kernel: [141294.374983] send process: page allocation stalls for 10108ms, orde…...

JUC并发工具类

一、ReentrantLock 特点&#xff1a;独占、可重入、公平/非公平、可中断、支持多个条件变量 1、常用api ReentrantLock实现了Lock接口&#xff0c;Lock类规范定义了如下方法 lock()&#xff1a;获取锁&#xff0c;调用该方法的线程会获取锁&#xff0c;当锁获得后&#xff0…...

【雕爷学编程】MicroPython动手做(10)——零基础学MaixPy之神经网络KPU

早上百度搜“神经网络KPU”&#xff0c;查到与非网的一篇文章《一文读懂APU/BPU/CPU/DPU/EPU/FPU/GPU等处理器》&#xff0c;介绍各种处理器非常详细&#xff0c;关于“KPU”的内容如下&#xff1a; KPU Knowledge Processing Unit。 嘉楠耘智&#xff08;canaan&#xff09;号…...