树的概念及结构|树的三种表示方法

前言

以前我们学的线性结构是一对一的线性关系,但现实中,还有一对多的情况要处理,那就是树形结构。今天我们将学习树的概念及结构、和树的三种常见表示方法。

一、树的概念及结构

1、树的概念

树是一种非线性的数据结构,它是由n(n >= 0)个有限结点组成的一个具有层次关系的集合。

(1)为什么把这种结构,叫做树呢?

答案是: 因为它的逻辑图看起来像一颗倒挂的树,根朝上,叶向下。如下图:

在这里插入图片描述

(2)空树

空树: n=0时称为空树。

(3)非空树

根节点: 有且仅有一个特定的结点,称为根(Root)节点。(根节点没有前驱结点)

树是递归实现的: 当n>1时,除根节点外,其余结点可分为m(m>0)个互不相交的有限集T1,T2,……Tm,其中每一个集合Ti(1<= i <=m)本身又是一颗树,并且称为根的子树(SubTree)。(每颗子树的根节点有且仅有一个前驱,可以有0个或多个后继)简单来说:任何一颗树都由根与子树组成。(没有子树就结束) 如下图:

在这里插入图片描述

(4)对于树的定义需要强调两点

对于任意一棵树根节点都是唯一,子树的根节点是子树的。

在树形结构中,子树之间一定是互不相交的,否则就不是树型结构。如下图:

在这里插入图片描述

(5)树的其他的表示形式(了解)

在这里插入图片描述

2、树的相关概念

在这里插入图片描述

  • 结点的度: 结点拥有的子树的个数称为结点的度。如上图:A的度为6。
  • 叶结点或终端结点: 度为0的结点称为叶子结点或终端结点。如上图:B、C、H、I……等结点为叶节点。
  • 分支结点或非终端结点: 度不为0的结点称为分支结点或非终端结点。(除了根节点外,分支节点也称内部结点。)如上图:D、E、F、G……等结点为分支节点。
  • 树的度: 树的度是树内各节点的度的最大值。如上图:树的度为6。
  • 孩子结点与双亲结点: 结点的子树的根称为该节点的孩子结点,相应的,该节点称为孩子结点的双亲结点。如上图:A是B的双亲结点,B是A的孩子结点。
  • 兄弟结点: 同一个双亲结点的孩子结点之间互称兄弟结点。如上图:B、C是兄弟结点。
  • 结点的祖先: 从根到该节点所经分支上所有结点。如上图A是所有结点的祖先。
  • 结点的子孙: 以某结点为根的子树中的任一结点都称为该结点的子孙。如上图:所有结点都是A的子孙。
  • 结点的层次: 从根开始定义起,根为第一层,根的孩子为第二层,以此类推。(数组我们是从0开始,为什么层次不从0开始呢——因为不符合我们平时的习惯,如以0开始,我们说根为第0层,那空树就得说-1层了,所以我们一般从1开始。)
  • 树的深度或高度: 树中节点的最大层次。如上图:树的高度为4。
  • 堂兄弟结点: 其双亲在同一层的结点互为堂兄弟。如上图:B、C、D、E、F、G互为堂兄弟。
  • 森林: 由m(m>=0)颗互不相交的树的集合称为森林。
  • 有序树与无序树: 如果将树中结点的各子树看成从左至右是有次序的,不能互换的,则称该树为有序树,否则称为无序树。

二、树的存储结构

树这种一对多的结构相对线性表就比较复杂了,要存储表示起来就比较麻烦了,既要保存值域,也要保存结点和结点之间的关系, 不过充分利用顺序存储和链式存储结构的特点,完全可以实现树的存储结构的表示。我们这里了解三种不同的表示法:双亲表示法、孩子表示法、孩子兄弟表示法。

1、双亲表示法

定义: 用一组连续空间存储树的节点,同时在每个结点中,附设一个指示器指示其双亲结点在表中的位置。结点结构如下图所示:

在这里插入图片描述
其中data是数据域,存储结点的数据信息。parent是指针域,存储该结点的双亲在数组中的下标,因为根节点没有双亲,所以我们约定根节点的位置域设置为-1。

实现: 树的结构需要有三个成员:结点数组、结点数、根的位置,所以我们将其定义为一个结构体。

双亲表示法的代码实现:

//树节点的数据类型
typedef int TElemType;
//结点结构
typedef struct PTNode
{TElemType data;//结点数据域int parent;//结点指针域,指向双亲的下标位置
}PTNode;//树结构
typedef struct PTree
{PTNode* a;//指向堆区开辟的节点数组int root;//根节点的位置int size;//结点数
}PTree;

如下图中树结构和树双亲表示所示:

在这里插入图片描述
优缺点:

优点:①找双亲容易;②顺序存储。

缺点:找孩子难,需要遍历整个结构。

2、孩子表示法

定义: 由于树中每个结点可能有多棵子树,可以考虑用多重链表,即每个结点有多个指针域,其中每个指针指向一棵子树的根节点,我们把这种方法叫做多重链表表示法。

因为树的每个结点的度,也就是它的孩子个数是不同的。所以我们有两种设计方案来解决。

方案一(树的度已知):结点同构 ——已知树的度为d,指针域的个数就等于树的度。其结构如下图:

在这里插入图片描述
其中data是数据域,child1到childd是指针域,用来指向该结点的孩子结点。

代码示例:

//已知树的度为N
#define N 5
//树的节点
typedef struct TreeNode
{struct TreeNode* child[N];//指针数组——存储孩子结点的位置int data;//存储数据
}TreeNode;

如下左图的树,树的度是3,所以指针域的个数是3,孩子表示如下右图所示:

在这里插入图片描述
如图我们可知这种方法当树中很多结点的度小于d时,结点中有很多指针域为空,空间浪费。

方案二(树的度未知):孩子表示法——理解两个结构:①孩子结点;②表头结点。然后使用顺序存储实现孩子表示法。 如图所示:

在这里插入图片描述

①孩子结点: 就是用单链表存储某个结点的所有孩子结点的地址(注:n个结点有n个孩子链表,如果是叶子结点则该链表为空。)结构如下所示:

在这里插入图片描述
②表头结点: 有两个成员:data成员存储某个结点的数据信息;firstchild成员存储该结点孩子链表的头指针。结构如图所示:

在这里插入图片描述
③树结构: 由三个成员组成:指向表头数组的指针a、保存根位置的root、保存节点数的size。

代码示例:

//孩子结点
typedef struct CTNode
{int child;//数据域,存储孩子结点在表头数组中的下标struct CTNode* next;//指向下一个孩子结点
}CTNode;//表头结点
typedef struct
{int data;//存储结点的数据CTNode* firstchild;//存储孩子链表的头指针
}CTBox;//树的结构
typedef struct
{CTBox* a;//指向堆区开辟表头数组int root;//根位置int size;//节点数
}Tree;

3、孩子兄弟法

定义: 我们观察发现,任意一棵树,它的节点的第一个孩子如果存在就是唯一,它的右兄弟如果存在也是唯一的。因此,我们设置两个指针,分别指向该结点的第一个孩子和此结点的右兄弟,也可叫做左兄弟右孩子法。结构如图所示:

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

typedef int DataType;
typedef struct TreeNode
{struct Node* firstChild1; // 第一个孩子结点struct Node* pNextBrother; // 指向其下一个兄弟结点DataType data; // 结点中的数据域
}TreeNode;

如下图树结构与孩子兄弟的表示:

在这里插入图片描述
总结:这三种表示方法就是分别从孩子、双亲、兄弟的角度设计的。

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

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

相关文章

数据结构——带头双向循环链表

呀哈喽&#xff0c;我是结衣。 前言 说到链表前面我们讲了单链表&#xff0c;但是链表可不止一种&#xff0c;要分类的话。链表可以分为带头或不带头&#xff0c;单向或双向&#xff0c;循环或者不循环&#xff0c;也就是说链表一共应该是有8种结构的&#xff0c;我们上次讲的…

vim批量多行缩进调整

网上其他教程&#xff1a; ctrl v 或者 v进行visual模式按方向键<&#xff0c;>调整光标位置选中缩进的行Shift > &#xff08;或者 Shift < &#xff09;进行左右缩进。 我只想说&#xff0c;乱七八糟&#xff0c;根本不管用 本文教程&#xff1a; 增加缩进…

HTTP/2.0协议详解

前言 HTTP/2.0&#xff1a;互联网通信的革新标准 随着互联网技术的飞速发展&#xff0c;HTTP协议作为互联网应用最广泛的通信协议&#xff0c;也在不断演进和优化。HTTP/2.0是HTTP协议的最新版本&#xff0c;它旨在提供更高效、更安全、更快速的互联网连接。 一、HTTP/2.0的…

深入理解JVM虚拟机第二十五篇:详解JVM方法的绑定机制静态绑定和动态绑定,早期绑定晚期绑定,并编写代码从字节码角度证明这件事情

大神链接&#xff1a;作者有幸结识技术大神孙哥为好友&#xff0c;获益匪浅。现在把孙哥视频分享给大家。 孙哥链接&#xff1a;孙哥个人主页 作者简介&#xff1a;一个颜值99分&#xff0c;只比孙哥差一点的程序员 本专栏简介&#xff1a;话不多说&#xff0c;让我们一起干翻J…

Windows系统隐藏窗口启动控制台程序

背景 上线项目有时候需要一些控制台应用作为辅助服务来协助UI应用满足实际需求&#xff0c;这时候如果一运行UI就冒出一系列的黑框&#xff0c;这将会导致客户被下的不起&#xff0c;生怕中了什么不知名病毒 方案 可以使用vbs来启动&#xff0c;这个是window系统自带的&#…

【2014年数据结构真题】

41. (13分&#xff09;二叉树的带权路径长度(WPL)是二叉树中所有叶结点的带权路径长度之和。 给定一棵二叉树T,采用二叉链表存储&#xff0c;结点结构如下&#xff1a; 其中叶结点的weight域保存该结点的非负权值。 设root为指向T的根结点的指针&#xff0c; 请设计求T 的WPL…

计算机 - - - 浏览器网页打开本地exe程序,网页打开微信,网页打开迅雷

效果 在电脑中安装了微信和迅雷&#xff0c;可以通过在地址栏中输入weixin:打开微信&#xff0c;输入magnet:打开迅雷。 同理&#xff1a;在网页中使用a标签&#xff0c;点击后跳转链接打开weixin:&#xff0c;也会同样打开微信。 运用同样的原理&#xff0c;在网页中点击超…

reactive和effect,依赖收集触发依赖

通过上一篇文章已经初始化项目&#xff0c;集成了ts和jest。本篇实现Vue3中响应式模块里的reactive方法。 前置知识要求 如果你熟练掌握Map, Set, Proxy, Reflect&#xff0c;可直接跳过这部分。 Map Map是一种用于存储键值对的集合&#xff0c;并且能够记住键的原始插入顺…

前端开发入门笔记(八)CSS3属性详解:动画详解+Flex布局图文详解+Web字体

参考链接&#xff1a;https://web.qianguyihao.com/02-CSS%E5%9F%BA%E7%A1%80/12-CSS3%E5%B1%9E%E6%80%A7%E8%AF%A6%E8%A7%A3%EF%BC%9A%E5%8A%A8%E7%94%BB%E8%AF%A6%E8%A7%A3.html#_3%E3%80%81%E6%97%8B%E8%BD%AC%EF%BC%9Arotate 过渡 transition的中文含义是过渡。过渡是CSS…

双写绕过 [极客大挑战 2019]BabySQL 1

打开题目 随便输入账号密码 根据报错信息可知这是单引号的字符型注入 那我们试试万能密码 1 or 11 页面报错 1 or 11 页面报错 而且根据报错内容显示是没有我们注入上去的or的 那我们就试试 1 order by 3 # 页面报错&#xff0c;根据报错显示页面过滤掉了or和by 那我们…

Dart利用私有构造函数_()创建单例模式

文章目录 类的构造函数_()函数dart中构造函数定义 类的构造函数 类的构造函数有两种&#xff1a; 1&#xff09;默认构造函数&#xff1a; 当实例化对象的时候&#xff0c;会自动调用的函数&#xff0c;构造函数的名称和类的名称相同&#xff0c;在一个类中默认构造函数只能由…

wpf devexpress设置行和编辑器

如下教程示范如何计算行布局&#xff0c;特定的表格单元编辑器&#xff0c;和格式化显示值。这个教程基于前一个文章 选择行显示 GridControl为所有字段生成行和绑定数据源&#xff0c;如果AutoGenerateColumns 属性选择AddNew。添加行到GridControl精确显示为特别的几行设置。…