一、树的基本概念
树型数据结构是一类重要的非线性数据结构,其中以树和二叉树最为常用。它描述了客观世界中事物之间的层次关系,树在计算机领域内也有广泛的应用,如在编译程序中,可用树表示源程序的语法结构。在数据库系统中的文件索引机构一般采用树来表示。
(一)树的定义
树(tree)是有n(n>=0)个结点组成的有限集合,该集合可用T来表示。当T非空时满足:
1、有且仅有一个特定的结点称为根(root)的结点;
2、除根结点外,其余结点可分为m(m>=0)个互不相交的有限集T1,T2,….Tm,其中每个集合本身有时一棵树,并且称为根的子树(subtree)(递归定义)。
(二)、树的表示方法
a) 图形树表示。
b) 二元组表示,即给出树中元素集合及这个集合上的关系。Tree=(D,R);D=(A,B,C,D,E,F,G,H,I,J,K,L,M);R={r};r={<A,B>,<A,C>, <A,D>,<B,E>,<B,F>,<E,K>,<E,L>,<C,G>,<D,H>,<D,I>,<D,J>,<H,M>
c) 集合关系的文氏图表示。
d) 广义表表示,(A,(B,(E(K,L),F),C(G),D,(H,(M),I,J)))
e) 凹入表表示。
(三)树的基本术语
a) 树的结点包含着一个数据元素及若干指向其子树的分支。
b) 某结点的子树的根称为结点的孩子结点(child),该结点称为孩子结点的双亲(parent)。具有同一双亲结点的孩子结点之间互称兄弟。
c) 结点的层次(level)从根开始定义,根为第一层,根的孩子为第二层,依次下推。树中结点的最大层次称为树的层数,亦可称为树的高度(或树的深度)。双亲在同一层次的结点互称为堂兄弟。
d) 结点拥有的子树称为该结点的度。树的度是树中各结点的度的最大值。
e) 度数为零的结点称为叶子(leaf)或终端结点,度大于零的结点称为分支结点或非终端结点。
f) 对子树的左右不加区别的树称作‘无序树’。对子树之间次序加以区别的树叫做有序树。
(四)树的存贮结构
树的存贮结构可用多重链表来实现,第个结点的链域取决于该结点的子树数,或者说取决于结点的度。
由于每个结点的度数不同,结点的长度也就不等,采用这种存贮结构就会使各种运算的算法变得复杂。如果取树的度为每个结点的链域个数,算法可以简化,但存贮空间浪费较大。树的存贮一般先转化为二叉树,再进行存贮。
二、二叉树
(一)、二叉树及其性质
1、二叉树(binary tree)是另一种树型结构,树中的每个结点至多只有二棵子树,并且二叉树的子树有左右之分,其次序不能颠倒。二叉树是n(n>=0)个结点的有限集,此集合或者为空集,或者由一个根结点和二个互不相交的左、右子树组成,且其左右子树也是一棵二叉树。
2、性质:(1)在二叉树的第i层上至多有2^(i-1)个结点(i>=1)。
(2)、深度为K的二叉树至多有2^K-1个结点(K>=1)。
(3)、对任一二叉树BT,如果其终端结点数为n0,度为2的结点树为n2,则n0=n2+1。
一棵深度为K且有(2^k)-1个结点的二叉树称为满二叉树。特点是每一层上的结点数都是最大结点数。
可以对满二叉树的结点进行连续编号。约定编号从根节点起,自上而下,自左至右进行。由此可引出完全二叉树的定义。深度为K的、有n个结点的二叉树,当且仅当其每一个结点都与深度为K的满二叉树中编号从1至n个结点一一对应时,称为完全二叉树。
完全二叉树的特点
(1)叶子结点只能在层次最大的两层上出现。
(2)对任一结点,若其右子树的最大层次为L,则其左子树的最大层次为L或L+1
性质:(4)具有n个结点的完全二叉树,其深度为log2n+1。
(5)如果对一棵有n个结点的完全二叉树(其深度为log2n+1)的结点按层次编号(从第一层到log2n+1层,每层从左到右),则对任一结点i ,有
1) 如果i=1,则结点i是二叉树的根,无双亲;如果i >1,则其双亲是结点i/2
2) 如果2i>n,则结点i无左孩子;否则,其左孩子是结点2i.
3) 如果2i+1>n,则结点i无右孩子;否则其右孩子是结点2i+1。
(6)、K层满二叉树非叶子结点(分支结点)总数为2^(k-1)-1。
(二)、二叉树的存储结构
1、顺序存储结构
用一组连续的存储单元存放二叉树中的元素,这这对于满二叉树和完全二叉树是非常适合的,我们将满二叉树中的节点进行编号。从根节点开始,自上而下,从左至右,并按其编号顺序存入一个一维数组之中。
根据完全二叉树的特征,结点在一维数组中的相对位置蕴含着结点之间的关系。
因为在顺序存储结构中是以结点在数组中的相对位置表示结点之间的关系。因此,一般的二叉树也必须按满二叉树的形式来存储,这样就会造成存储空间的浪费。
2、链式存储结构
在二叉树的链式存储结构中,包含一个数据元素和分别指向其左、右子树的两个分支。每个结点包括三个域——数据域和左、右孩子指针域。有时,为了寻找某个结点的双亲结点,还可以在结点结构中增设一个指向其双亲结点的指针域。
链表存储二叉树,存储空间也没有得到充分利用。当左子树或右子树为空时就会有空链。。含有n个结点的二叉树,将会有n+1个空指针存在。可以利用这些存放空指针的空链域来存放其他又用信息,从而得到另一种存储结构——线索链表。
(三)、树和二叉树之间的转换
1、树的存贮结构
(1)双亲表示法
利用了每个结点(除根结点外)只有唯一双亲的特点,用二维数组来存贮一棵一般的树。这种结构对于寻求某结点的双亲及求树的根结点等操作是很方便的,但用于求结点的孩子时比较麻烦,需要遍历整个数位。(如:)
结点 data parent
1 1 0
2 2 1
3 3 1
4 4 2
5 5 2
6 6 3
7 7 5
8 8 5
9 9 5
(2)孩子表示法
孩子表示是用多重链表来存贮一般树。在多重链表中,每个结点有多个指针域指向一棵子树的根结点,此时链表中的结点可以有如下两种结点结构。第一种结构,多重链表中的结点是同构的,其中d是树的度。由于树中很多空链域,存贮空间较浪费。例如,对于度为K的树,共有n个结点,因为每个结点都有固定的K个链域,那么,n个结点共有Kn个链域。另一方面,n个结点仅需要n-1个链(根结点除外)来链接,因此空链域数为Nk-(n-1)=n(K-1)+1。当K=3时,空链域数为2n+1,即有多于2/3的空链域。
Data child1 child2 …… ……. …… child d
第二种结点结构,则多重链表中的结点是不同构的。其中d为结点的度。Degree域的值同d。此时,虽然能够节约存贮空间,但操作不方便。
Data degree child1 child …… …. .. . . . .. child d
(3) 孩子兄弟表示法
一般树可采用先转换成二叉树后进行存贮。结点结构包换数据域data、结点的两个链域,第一个指向该结点的第一个孩子,第二个链域指向该结点的下一个兄弟。
O
A D
B C E F G
K H J
转换为二叉树
O^
A
^B D^
C^ E
^K^ ^H^ F
^J^ ^G^
另一方法:除了最左边的分枝点外,删去所有从每一个结点长出分枝。在同一层次中,兄弟结点之间从左到右的有向边连接,选定二叉树的左儿子和右儿子如下:直接处于给定结点下面的结点作为左儿子,对于同一水平线上与给定结点右邻的结点,作为右儿子。
2、森林转换成二叉树
通过树的孩子兄弟表示法,可以将树转换成二叉树。由于树的根结点没有兄弟,被转换的二叉树其右子树必定为空。如果将森林中的其它树的根看成是第一棵树根的兄弟,则可导出森林和二叉树之间的转换。
转换规则:如果F={T1,T2..Tm}是森林,B={root,LB,RB}
若F为空,即m=0,则B为空树。
若F非空,即m<>0,则B的根即为森林中第一棵树的根ROOT(T1),B的左孩子LB是从森林F1={T11,T12,…,T1m}转换而成的二叉树,右子树RB是从森林F’={T2,T3,…,Tm}转换而成的二叉树。
A E G
B C D F H I
J
树与二叉树对应
A^ E^ G^
^B F ^H
^C I^
^D J^
森林与二叉树的对应
A
B E
C F G
D H
I
J
3、二叉树转换成森林
如果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转换而成的森林。