赞
踩
树是一种非常重要的非线性结构,它在计算机领域的应用十分广泛,如在编译程序或数据库程序中。树形结构具有分支性(分支性是由于一个或多个或多个结点存在两个或两个以上直接后继节点)和层次性(层次性是由分支产生并呈现出来的)两大特点。
(1)树是由有限个结点(即数据元素)组成的集合。若这一集合的结点个数为0,则我们称该树为空树;否则为非空树
(2)非空树的特点:a.有且仅有一个称为树根的结点(简称”根节点“),该节点无任何先驱结点
b.当结点数目大于1时,除了根节点之外的其余结点被分成若干个互不相交的有限集合,这些有限集合均可被视为一棵独立的树,他们被称为根结点的子树
如图1和图2,当忽略掉图1中的根节点A后,就变为了图2中的以B为根节点的树T1和以C为根结点的树T2,T1和T2都是结点A的子树
(1)结点的度:结点拥有的子树的数目称为结点的度。如图1 的A结点的度数为2
(2)叶子结点:度数为0的结点称为叶子结点,叶子结点没有后继节点。如图1,H、I、J、K、L、M、N、O都是叶子结点
(3)分支结点:除根结点外度数为0的结点
(4)树的度:一棵树中度数最大的结点的度
(5)孩子结点:树中任一结点的子树的根节点被称为这一结点的孩子结点
(6)双亲结点:也称父节点,即拥有孩子结点的结点结点
(7)兄弟结点:同一个父节点的所有结点,如图1的B、C结点互为兄弟系欸但
(8)祖先结点:从根节点到树中任一节点所经过的所有结点被称为该结点的祖先结点,如图1中,H的祖先结点为A、B、D
(9)子孙结点:树中以某一结点为根的子树中任一结点均被称为该结点的子孙结点
(10)结点的层次:从根结点开始定义,通常将根结点所在的层次称为第一层,根结点的孩子结点为第二层,依此类推,若某一结点在第i层(该结点不是叶子结点),则其子树的根在第i+1层
(11)堂兄弟结点:顾名思义,在同一层次上,但是父节点不同的所有结点,例如图一中B、F是一对堂兄弟结点
(12)树的深度(高度):树中所有结点层次的最大值
(13)左子树和右子树:根节点的左边的子树称为左子树,右边的子树称为右子树
(14)有序树和无序树:交换左右子树的位置,不影响原来的树的树称为无序树,否则称为有序树,即看他们的位置能否随意改变
(15)长子:有序树中,一个结点如果有孩子结点,我们规定它的最左边的孩子结点为长子,如图1中,A的长子结点为B
(16)右兄弟:有序树中,一个结点如果有两个以上的结点,则右边的结点为其左边第一个结点的右兄弟,如图1中,B的右兄弟为C
(17)树结点的下标:我们一般规定按照树的层次从小到大,同一层次从左到右,从0开始为每一个树结点赋予一个下标
(1)树中的结点数目等于所有的结点的度加1
(2)度为K的树中第i( i ≥ 1 i\geq1 i≥1)层上最多有 k i − 1 k^{i-1} ki−1个结点
(3)深度为h的度为k的树最多有 k h − 1 k − 1 \frac {k^h-1}{k-1} k−1kh−1个结点
(4)具有n个结点的度为k的树的最小深度为 ⌈ log k ( n ( k − 1 ) + 1 ) ⌉ \lceil \log_{k}{(n(k-1)+1)}\rceil ⌈logk(n(k−1)+1)⌉(即为不小于 log k ( n ( k − 1 ) + 1 ) \log_{k}{(n(k-1)+1)} logk(n(k−1)+1)的最小整数
1.双亲表示法
(1)双亲表示法也可以叫做父节点表示法,即在存储树的结点时,包括两个部分,结点值data和该结点的双亲(也称为父节点)parent。我们在存储时使用一组连续的存储单元存储树的每一个结点以及结点之间的关系。
如图3就时存储图4这颗树的双亲表示法,在存储时对于根节点,由于根节点没有父节点,所以我们对它的父节点下标我们设置为特殊值-1,当然这个特殊值可以由自己设置
(2)我们可以定义一个类来表示树的结点,代码如下class TreeNode(): def __init__(self, date, parent): self.date = date #存放数据 self.parent = parent #存放父节点的下标
- 1
- 2
- 3
- 4
(3)由于这种存储结构是以树中每一个节点(除根节点外)均只有唯一父节点为前提的。因此在使用数组实现这一存储结构时,我们会发现在求某个结点的父节点时很容易,但在求某个节点的孩子结点时,最坏情况要访问整个数组。
2.孩子表示法
(1)孩子表示法与双亲结点表示法类似,都是需要另外开辟一个新的空间来存储结点信息,不过孩子表示法开辟的另外的空间顾名思义就是保存它孩子结点的信息,不过一个结点可能有多个孩子结点,所以我们这里就需要用到单链表与数组相结合,以图5这棵树为例
图6就是它的孩子表示法,我们创建一个列表来存储两个信息,一个是它的本身的数据(date域),另一个则是它孩子结点的下标(index域),孩子结点的下标我们可以用单链表来存储,比如A结点的孩子结点有B(下标为1)和C(下标为2),然后我们便在它的index域存储1和2这两个信息
(2)孩子表示法的优点就是查找某结点的孩子结点很方便,其缺点是在查找某个结点的父节点时,最坏情况需要访问所有的列表元素及链表结点
(3)我们在实现孩子表示法时定义了两个类,一个是TreeNode类,用来表示树的结点,另一个是ChildNode类,用来表示组成孩子链表的孩子结点,实现的代码如下:class TreeNode(): def __init__(self, date): self.date = date # 存放该节点的数据 self.child = None # 存放它的第一个孩子结点的下标 class ChildNode(): def __init__(self, index): self.index = index # 存放孩子结点的位置下标 self.next = None # 存放它的兄弟结点位置的下标
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
3.孩子兄弟表示法
(1)孩子兄弟表示(又被称为二叉树表示法或二叉链表示法),在存储树的结点时,我们包含4个部分:一个是存储该结点数据的数据域date,第二个是指向它的第一个孩子结点(长子结点)的结点域pFirstChild,第三个是指向它的兄弟结点(右兄弟)的结点域BrotherNode,第四个则是指向它的父节点的结点域Father
(2)以图5为例,它的孩子兄弟表示法可以用图7表示出来:
(3)该表示法兼顾了孩子表示法和双亲表示法的所有优点,在查找某个结点的父节点时方便,在查找某个结点的孩子结点或兄弟结点时都很方便,不过就是实现起来稍微复杂点而已
(4)我们定义一个TreeNode类来表示孩子兄弟表示法的树结点类型,代码实现如下:class TreeNode(): def __init__(self, date, Child=None, Brother=None, Father=None): self.date = date self.pFirstChild = Child self.BrotherNode = Brother self.Father = Father
- 1
- 2
- 3
- 4
- 5
- 6
树的遍历是指按某种方式访问树中的所有结点,并且要求树中每一个结点只被访问一次。树的遍历方式主要有先序(根)遍历、后序(根)遍历,层次遍历,接下来我们都以图5这棵树为例子讲述
1.先序遍历
先序遍历可以简述为根左右,即:
(1)先访问根节点
(2)按照从左到右的顺序先序遍历根节点的每一棵树
图5这课树先根遍历得到的结点序列为:ABCDEGF2.后序遍历
后序遍历可以简述为左右根,即:
(1)按照从左到右的顺序后序遍历根节点的每一棵树
(2)访问根节点
图5这课树后根遍历得到的结点序列为:BDGEFCA3.层次遍历
层次遍历的过程是从根节点开始,按结点所在层次的从小到大,同一层从左到右的次序访问树中的每一个结点
图5这棵树的层次遍历得到的结点序列为:ABCDEG
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。