首页计算机计算机基础数据结构-C#语言描述 05 第05章 树.pptx

05 第05章 树.pptx

页数:36页文件大小:570.2 KB来源: 数据结构-C#语言描述ppt课件

本课件讲解树形结构这一典型的一对多非线性结构。内容从树的递归定义与四类表示方法入手,梳理结点度、层次、深度等基本术语,进而讲解二叉树的五种基本形态、满二叉树与完全二叉树、顺序与链式三类存储结构,图解先序、中序、后序与广度优先四种遍历,并说明线索二叉树的构造及树、森林与二叉树的相互转换。

第五章树章节封面,引出树的定义、二叉树、遍历与森林转换四条主线
树形结构引入页,用司令军长师长的编制说明元素间一对多的层次关系
树的定义页,给出根结点与互不相交子树的递归定义并说明其递归特性
查看本课件的文字版(共 36 页,供检索与复制)

第1页:第五章树封面

本页为第五章树封面。本章讲解树的基本概念、二叉树及其存储结构、二叉树的遍历、线索二叉树,以及树和森林的存储与相互转换。

第2页:树形结构的引入

数据结构中使用树形结构来表示元素间的一对多的关系。

课件以军队编制为例:司令之下辖若干军长,每个军长之下又辖若干师长,上下级之间形成清晰的分支层次,这正是树形结构的典型形态。

第3页:树的定义

树(Tree)是 n(n≥0)个结点(Node)的有限集。在任意一棵非空树中,有且仅有一个特定的称为根(Root)的结点;当 n>1 时,其余结点分成 m(m>0)个互不相交的有限集 T1,T2,…,Tm,其中每一个集合本身又是一棵树,并且称为根的子树。

树的定义是递归的,即在树的定义中又用到了树的概念,它刻画了树的固有特性,即一棵树由若干棵子树构成,而子树又由更小的若干棵子树构成。

第4页:树的表示

同一棵树可以用四种方式表示:

  • 树形表示法:用结点与分支画出层次
  • 凹入表示法:用缩进表示结点所在层次
  • 文氏图表示法:用集合的包含关系表示
  • 括号表示法:如 (A(B(D(I),E),C(F,G,H)))

第5页:树的术语:度与叶子

树的结点
数据元素的内容及指向其子树的分支统称为结点
结点的度
在树中,结点拥有子树的个数称为结点的度
树的度
树的度是树内各结点的度的最大值
叶子或终端结点
度为 0 的结点称为叶子或终端结点

第6页:树的术语:结点关系

非终端结点或分支结点
度不为 0 的结点称为非终端结点或分支结点。除根结点之外,分支结点也称为内部结点
孩子、双亲
结点的子树的根称为该结点的孩子,该结点称为孩子的双亲或父亲
兄弟
同一个双亲的孩子称为兄弟
祖先和子孙
结点的祖先是从根到该结点所经分支上的所有结点;以某结点为根的子树中的任一结点都称为该结点的子孙

第7页:层数、堂兄弟与深度

层数、堂兄弟
从根结点开始定义,根为第一层,根的孩子为第二层,其余结点的层数为双亲结点的层数加 1。双亲在同一层上的结点互为堂兄弟
树的深度
树结点中的最大层数称为树的深度

第8页:有序树和无序树

如果树中结点的各子树从左至右是有次序的(即不能互换),则称该树为有序树,否则称为无序树。

图中 (a)(b) 两棵树的结点相同但左右子树次序不同,在有序树的意义下它们是两棵不同的树。

第9页:森林

森林为有限棵树的集合。

对树而言,删去其根结点,就得到一个森林;对森林而言,加上一个结点作为根就变为一棵树。这一性质是树、森林与二叉树相互转换的基础。

第10页:二叉树的基本概念

二叉树的特点是每个结点至多有两棵子树(即二叉树不存在度大于 2 的结点),并且二叉树的子树有左右之分,其次序不能任意颠倒,即如果将其左右子树颠倒,就成为另一棵不同的二叉树。即使树中结点只有一棵子树,也要区分它是左子树还是右子树。

因此,二叉树具有五种基本形态:空二叉树、仅有根结点的二叉树、右子树为空的二叉树、左子树为空的二叉树、左右子树非空的二叉树。

第11页:满二叉树

在一棵二叉树中,如果所有分支结点都同时具有左孩子和右孩子,并且所有叶子结点都在同一层上,这种树的特点是每层上的结点数是最大结点数,称为满二叉树(Full Binary Tree)。

第12页:完全二叉树

完全二叉树只允许树的最后一层出现空结点,且最下层的叶子结点集中在树的左部。

显然,一棵满二叉树必定是一棵完全二叉树,而完全二叉树未必是满二叉树。图中右侧因最下层叶子未靠左连续排列,属于非完全二叉树。

第13页:顺序存储结构的编号性质

把一个满二叉树自上而下、从左到右顺序编号,依次存放在数组内。设满二叉树结点在数组中的索引号为 i,那么有如下性质:

  1. 如果 i = 0,此结点为根结点,无双亲
  2. 如果 i > 0,则其双亲结点为 (i-1) / 2(注意,这里的除法是整除,结果中的小数部分会被舍弃)
  3. 结点 i 的左孩子为 2i + 1,右孩子为 2i + 2
  4. 如果 i > 0,当 i 为奇数时,它是双亲结点的左孩子,它的兄弟为 i + 1;当 i 为偶数时,它是双亲结点的右孩子,它的兄弟结点为 i-1
  5. 深度为 k 的满二叉树需要长度为 2 的 k 次方减 1 的数组进行存储

第14页:满二叉树与一般二叉树的存储

图中 (a) 为满二叉树,按层编号后数组下标与结点一一对应,空间利用率最高;(b) 为一般二叉树,缺失的结点在数组中留下空位,仍要占用存储单元。

一个深度为 k 的二叉树需要 2 的 k 次方减 1 个存储空间,因此顺序存储只适合形态接近满二叉树的情形。

第15页:链式存储:二叉链表

二叉树的链式存储结构可分为二叉链表和三叉链表。二叉链表中,每个结点除了存储本身的数据外,还应该设置两个指针域 left 和 right,它们分别指向左孩子和右孩子。

图中给出二叉树与其对应的二叉链表:从 head 出发沿 left、right 指针即可访问整棵树,但无法直接找到双亲。

第16页:链式存储:三叉链表

如果在二叉树中经常需要寻找某结点的双亲,每个结点还可以加一个指向双亲的指针域 parent,这就是三叉链表。

三叉链表的结点含 data、left、right 与 parent 四个域,代价是每个结点多占用一个指针空间。

第17页:链式存储:双亲链表

双亲链表只存储结点的双亲信息而不存储孩子信息。下表给出双亲链表的存储结构:

双亲链表存储结构表
数组下标dataparenttag
0A-1—
1B0L
2C0R
3D1L
4E1R
5F2R

其中 parent 为 -1 表示根结点,tag 用 L、R 标记该结点是双亲的左孩子还是右孩子。

第18页:二叉树遍历的概念

二叉树遍历(Traversal)就是按某种顺序对树中每个结点访问且只能访问一次的过程。访问的含义很广,如查询、计算、修改、输出结点的值。

树遍历本质上是将非线性结构线性化,它是二叉树各种运算和操作的实现基础。

第19页:深度优先遍历路线

本页给出二叉树的深度优先遍历路线:沿树的外围走一圈,每个结点被经过三次,分别在第一次、第二次、第三次经过时访问,就得到先序、中序、后序三种遍历序列。

第20页:先序遍历过程

先序遍历过程:

  1. 访问根结点
  2. 先序遍历左子树
  3. 先序遍历右子树

先序遍历中根结点最先被访问,因此得到的序列的第一个元素一定是整棵树的根。

第21页:先序遍历序列

按“根—左—右”的顺序访问,图中二叉树的先序遍历序列为:ABDECF。

先序遍历的特点是第一个访问到的必定是根结点,常用于复制树和输出树形目录。

第22页:中序遍历过程

中序遍历过程:

  1. 中序遍历左子树
  2. 访问根结点
  3. 中序遍历右子树

中序遍历把根结点夹在左右子树之间访问,序列次序为左子树、根、右子树。

第23页:中序遍历序列

按“左—根—右”的顺序访问,图中二叉树的中序遍历序列为:DBEACF。

对二叉查找树做中序遍历,可以得到按关键字递增排列的有序序列。

第24页:后序遍历过程

后序遍历过程:

  1. 后序遍历左子树
  2. 后序遍历右子树
  3. 访问根结点

后序遍历中左右子树的结点一律先于根结点被访问,根结点是序列的最后一项。

第25页:后序遍历序列

按“左—右—根”的顺序访问,图中二叉树的后序遍历序列为:DEBFCA。

后序遍历最后访问根结点,常用于释放整棵树、计算子树规模等需要先处理孩子的场景。

第26页:广度优先遍历

由于二叉树结点分属不同的层次,因此可以从上到下、从左到右依次按层访问每个结点。

它的访问顺序正好和二叉树顺序存储结构中结点在数组中的存放顺序相吻合。图中二叉树使用广度优先遍历访问的顺序为:ABCDEF。

第27页:线索二叉树的定义

线索二叉树的结点含 data、left、right 及两个标志位 ltag、rtag:

  • ltag 为 0:left 指向结点的左孩子;ltag 为 1:left 指向结点的前驱结点
  • rtag 为 0:right 指向结点的右孩子;rtag 为 1:right 指向结点的后继结点

利用标志位可以把遍历中得到的线性前驱后继信息直接存入空的指针域。

第28页:中序线索二叉树

图中 (a) 为原二叉树,(b) 为其中序遍历结果 DBEACF,(c) 为线索化后的二叉树。

线索化后,原本为空的指针域改为指向该结点在某种遍历序列中的前驱或后继,从而可以不用递归、不用栈地完成遍历。

第29页:树的存储:双亲表示法

在一棵树中,任意一个结点的双亲只有一个,这是由树的定义决定的。双亲表示法正是利用了树的这种性质,在存储结点信息的同时,在每个结点中附设一个指向其双亲的指针,指示双亲在链表中的位置。这种结构一般借助数组来实现,这样的链表也称为静态链表。

树的双亲表示法存储表
数组下标dataparent
0A-1
1B0
2C0
3D0
4E1
5F1
6G1
7H3
8I3

parent 为 -1 表示该结点为根结点。

第30页:树的存储:孩子表示法

树的每个结点都有自己的孩子,孩子表示法是指在树的每个结点中设置指针指向该结点的孩子。由于一般树中的结点可能存在多个孩子,因此需要使用链表依次存储结点的所有孩子。

孩子链表的存储结构需同时使用数组和单链表来实现:数组存放各结点,每个结点再挂一条由其孩子组成的单链表。

第31页:双亲孩子链表表示法

树的双亲孩子链表表示法把双亲表示法与孩子表示法结合起来:数组中的每个结点既保存其双亲的位置,又通过链表串起它所有的孩子。

这样既能快速找到双亲,也能方便地遍历某个结点的全部孩子。

第32页:孩子兄弟表示法

孩子兄弟表示法在每个结点中设置两个指针域:firstChild 指向该结点的第一个孩子,nextSibling 指向该结点的下一个兄弟,二者与 data 共同构成结点结构。

由于每个结点只有两个指针域,这种表示法可以直接把一般树看成二叉树来处理,是树与二叉树转换的桥梁。

第33页:一般树转换为二叉树

一般树转换为二叉树的步骤如下:

  1. 连线:在所有兄弟结点之间加一条连线
  2. 切线:对于每个结点,除了保留与其最左孩子的连线外,去掉该结点与其他孩子之间的连线
  3. 旋转:将所有水平方向连线顺时针旋转 45°,就可以得到一棵形式上更为清楚的二叉树

第34页:森林转换为二叉树

森林转换为二叉树时,先把森林中每一棵树各自转换为二叉树,再把各棵二叉树的根结点依次用右链相连,最后整体旋转即得到一棵二叉树。

转换后,二叉树的根的左子树对应第一棵树的子树,右链上依次挂着其余各棵树。

第35页:二叉树还原为一般树

二叉树还原为一般树是一般树转换为二叉树的逆过程:沿左链把结点恢复为双亲的孩子,沿右链把结点恢复为兄弟关系,旋转后即得到原来的一般树。

第36页:二叉树还原为森林

将一棵由森林转化得到的二叉树还原为森林的步骤如下:

  • 将二叉树根结点与沿着其右链不断地搜索到的所有右孩子的连线全部抹去,这样就得到包含若干棵二叉树的森林
  • 将每棵二叉树还原为一般树,这样就可以得到森林
顶部目录