总结六:数据结构-树和二叉树

一、树的定义和基本术语

1.1 树的定义

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

1.2 树的基本术语

         树的结点包含一个数据元素及若干指向其子树的分支。结点拥有的子树树称为结点的度。度为0的结点称为叶子终端结点。度不为0的结点称为非终端结点分支结点。除根节点之外,分支结点也称为内部结点树的度是树内各结点的度的最大值。结点的子树的根称为该结点的孩子,相应地,该结点称为孩子的双亲。同一个双亲的孩子之间互称兄弟。结点的祖先是从根结点到该结点所经分支上的所有结点。反之,以某结点为根的子树中的任一结点都成为该结点的子孙

         结点的层次从根开始定义起,根为第一层,根的孩子为第二层。其双亲在同一层的结点互为堂兄弟。树中结点的最大层次称为树的深度高度

         如果将树中结点的各子树看成从左至右是有次序的,则称该树为有序树,否则称为无序树。在有序树中最左边的子树的根称为第一个孩子,最右边的称为最后一个孩子。

         森林是m(m>=0)棵互不相交的树的集合。

二、二叉树

2.1 二叉树的定义

         二叉树是另一种树型结构,它的特点是每个结点至多只有两颗子树,并且,二叉树的子树有左右之分,其次序不能任意颠倒。

         二叉树可以有五种基本形态:

(a)空二叉树

(b)仅有根结点的二叉树

(c)右子树为空的二叉树

(d)左右子树均非空的二叉树

(e)左子树为空的二叉树

         一棵深度为k且有2k-1个结点的二叉树称为满二叉树。可以对满二叉树的结点进行连续编号,约定编号从根节点起,自上而下,自左至右。由此可引出完全二叉树的定义。深度为k的,有n个结点的二叉树,当且仅当其每一个结点都与深度为k的满二叉树中编号从1至n的结点一一对应时,称之为完全二叉树

         (a)满二叉树

         (b)完全二叉树

         (c)非完全二叉树

2.2 二叉树的性质

         性质一:在二叉树的第i层上至多有2i-1个结点(i>=1)

         性质二:深度为k的二叉树至多有2k-1个结点(k>=1)

         性质三:对任何一棵二叉树T,如果其终端结点数为n0,度为2的结点数为n2,则n0 = n2 + 1

         性质四:具有n个结点的完全二叉树的深度为log2n+1

         性质五:如果对一棵有n个结点的完全二叉树(其深度为log2n+1)的结点按层序编号(从第1层到第log2n+1层,每层从左到右),则对任一结点i(1<=i<=n),有

         (1)如果i=1,则结点i是二叉树的根,无双亲;如果i>1,则其双亲是结点i/2

       (2)如果2i>n,则结点i无左孩子(结点i为叶子结点);否则其左孩子是结点2i

       3)如果2i+1>n,则结点i无右孩子;否则其右孩子是结点2i+1

2.3 二叉树的存储结构

2.3.1 顺序存储结构

         按照完全二叉树的编号规则,进行线性顺序存储。这种存储结构仅适用于完全二叉树。因为,在最坏的情况下,一个深度为k且只有k个结点的单支树,却需要长度为2k-1的一维数组。

         (a)完全二叉树

         (b)一般二叉树

2.3.2 链式存储结构

         (a)二叉链表

二叉树的链表中的结点至少包含3个域:数据域、左指针域和右指针域。

         (b)三叉链表

有时,为了便于找到结点的双亲,则还可在结点结构中增加一个指向其双亲的指针域。

三、遍历二叉树和线索二叉树

3.1 遍历二叉树

         若限定先左后右,分别称之为先(根)序遍历,中(根)序遍历和后(根)序遍历。基于二叉树的递归定义,可得下述遍历二叉树的递归算法定义。

         先序遍历二叉树的操作定义为:

         若二叉树为空,则空操作;否则

         (1)访问根节点;

         (2)先序遍历左子树;

         (3)先序遍历右子树。

中序遍历二叉树的操作定义为:

         若二叉树为空,则空操作;否则

         (1)中序遍历左子树;

(2)访问根节点;      

         (3)中序遍历右子树。

后序遍历二叉树的操作定义为:

         若二叉树为空,则空操作;否则

         (1)后序遍历左子树;

         (2)后序遍历右子树;

(3)访问根节点。

 

例如:

(a)先序遍历

– + a * b – c d / e f

(b)中序遍历

a + b * c – d – e / f

(c)后序遍历

a b c d – * + e f / –

3.2 线索二叉树

         遍历二叉树是以一定规则将二叉树中结点排列成一个线性序列,得到二叉树中结点的先序序列或中序序列或后序序列。这实质上是对一个非线性结构进行线性化操作,使每个结点(除第一个和最后一个外)在这些线性序列中有且仅有一个直接前趋和直接后继。

         方法有两个,第一个,最简单的办法是在每个结点上增加连个指针域,分别只是结点在依托一次序遍历时得到的前趋和后继信息,显然,这样做使得结构的存储密度大大降低。第二个,在有n个结点的二叉链表中必定存在n+1个空链域,由此可以利用这些空链域来存放节点的前趋和后继的信息。

         以第二种方法为例:规定若结点有左子树,则其lchild域指示其左孩子,否则令lchild域指示其前趋;若结点有右子树,则其rchild域指示其右孩子,否则令rchild域指示其后继。为了避免混淆,尚需改变结点结构,增加两个标志域。

         其中,ltag = 0:lchild域指示结点的左孩子;ltag = 1:lchild域指示结点的前趋;rtag = 0:rchild域指示结点的右孩子;rtag = 1:rchild域指示结点的后继。

         以这种结点结构构成的二叉链表作为二叉树的存储结构,叫做线索链表,其中指向结点前趋和后继的指针,叫做线索。加上线索的二叉树称之为线索二叉树。对二叉树以某种次序遍历使其变为线索二叉树的过程叫做线索化

 

例如:中序遍历二叉树

         (a)中序线索二叉树

         (b)中序线索链表

四、树和森林

4.1 树的存储结构

         以下面这棵树为例进行阐述。

4.1.1 双亲表示法

         假设以一组连续空间存储树的结点,同时在每个结点中附设一个指示器指示其双亲结点在链表中的位置。但是,在这种表示法中,求结点的孩子时需要遍历整个结构。

4.1.2 孩子表示法

         (a)无表示“度”的域:多重链表中的结点是同构的,其中d为树的度。由于树中很多结点的度小于d,所以链表中有很多空链域,空间较浪费,不难推出,在一棵有n个结点度为k的树中必有n(k-1)+1个空链域。

         (b)有表示“度”的域:多重链表中的结点是不同构的,其中d为结点的度,degree域的值同d,此时,虽能节约空间,但操作不方便。

         (c)不含双亲的孩子链表:把每个结点的孩子结点排列起来,看成是一个线性表,且以单链表作存储结构,则n个结点有n个孩子链表。而n个头指针又组成一个线性表,为了方便查找,可采用顺序存储结构。

         (d)含双亲的孩子链表:孩子表示法便于那些涉及孩子的操作的实现,却不适用于双亲的操作。我们可以把双亲表示法和孩子表示法结合起来。

4.1.3 孩子兄弟表示法

         又称二叉树表示法,或二叉链表表示法。即以二叉链表作树的存储结构。链表中结点的两个链域分别指向该结点的第一个孩子结点和下一个兄弟结点。

4.2 森林和二叉树的转换

         由于二叉树和树都可用二叉链表作为存储结构,则以二叉链表作为媒介可导出树与二叉树之间的一个对应关系。也就是说,给定一棵树,可以找到唯一的一棵二叉树与之对应,从物理结构来看,它们的二叉链表是相同的,只是解释不通而已。

         (a)森林转换成二叉树

         如果F = {T1,T2,…,Tm}是森林,则可按如下规则转换成一棵二叉树B = (root,LB,RB)。第一:若F为空,即m = 0,则B为空树;第二:若F非空,即m ≠ 0,则B的根root即为森林中第一棵树的根ROOT(T1);B的左子树LB是从T1中根结点的子树森林F1 = {T11,T12,…,Tm1}转换而成的二叉树;其右子树RB是从F’ = {T2,T3,…,Tm}转换而成的二叉树。

         (b)二叉树转换成森林

         如果B = (root,LB,RB)是一棵二叉树,则可按如下规则转换成森林F = {T1,T2,…,Tm}。第一:若B为空,则F为空;第二:若B非空,则F中第一棵树T1的根ROOT(T1)即为二叉树B的根root;T1中根结点的子树森林F1是由B的左子树LB转换而成的森林;F中除T1之外其余树组成的森林F’ = {T2,T3,…,Tm}是由B的右子树RB转换而成的森林。

4.3 树和森林的遍历

4.3.1 树的遍历

         由树结构的定义可引出两种次序遍历树的方法。

         (a)先根(次序)遍历:即先访问树的根结点,然后依次先根遍历根的每棵子树。

         (b)后根(次序)遍历:即先依次后根遍历每棵子树,然后访问根结点。

4.3.2 森林的遍历

         按照森林和树相互递归的定义,我们可以推出森林的两种遍历方法。

(a)先序遍历森林

若森林非空,则可按下述规则遍历:

第一:访问森林中第一棵树的根结点;

第二:先序遍历第一棵树中根结点的子树森林;

第三:先序遍历除去第一棵树之后剩余的树构成的森林。

(b)中序遍历森林

如森林非空,则可按下述规则遍历:

第一:中序遍历森林中第一棵树的根结点的子树森林;

第二:访问第一棵树的根结点;

第三:中序遍历除去第一棵树之后剩余的树构成的森林。

当森林转换成二叉树时,其第一棵树的子树森林转换成左子树,剩余的森林转换成右子树,则上述森林的先序和中序遍历即为其对应的二叉树的先序和中序遍历。

五、赫夫曼树及其应用

5.1 最优二叉树(赫夫曼树)

         从树中一个结点到另一个结点之间的分支构成这两个结点之间的路径,路径上的分支数目称做路径长度树的路径长度是从树根到每一结点的路径长度之和。树的带权路径长度是树中所有叶子结点的带权路径长度之和,通常记作WPL = wklk。假设有n个权值{w1,w2,…,wn},试构造一棵有n个叶子结点的二叉树,每个叶子结点带权为wi,则其中带权路径长度WPL最小的二叉树称做最优二叉树赫夫曼树

         (a)WPL = 7*2+5*2+2*2+4*2 = 36

         (b)WPL = 7*3+5*3+2*1+4*2 = 46

         (c)WPL = 7*1+5*2+2*3+4*3 = 35

         赫夫曼算法:

         (1)根据给定的n个权值{w1,w2,…,wn}构成n棵二叉树的集合F={T1,T2,…,Tn},其中每棵二叉树Ti中只有一个带权为wi的根结点,其左右子树均空。

         (2)在F中选取两棵根结点的权值最小的树作为左右子树构造一棵新的二叉树,且置新的二叉树的根结点的权值为其左、右子树上根结点的权值之和。

         (3)在F中删除这两棵树,同时将新得到的二叉树加入F中。

         (4)重复(2)和(3),直到F只含一棵树为止。这棵树便是赫夫曼树。

5.2 赫夫曼编码

编码:a:0;b:10;c:110;d:111

猜你喜欢

转载自blog.csdn.net/LittleFlown/article/details/84075202