算法与数据结构第4章树与二叉树树型结构前面几章相继介绍讨论的几种数据结构都属于线性结构,而在实际应用中的许多问题若采用非线性结构来表示会显得更加明确和方便。所谓非线性结构是指:在该类结构中至少存在一个数据元素有两个或多个的直接前驱(或直接后继)元素。树型结构就是其中一类十分重要的非线性结构,树型结构它可用来描述客观世界中广泛存在的许许多多分等级、呈现层次结构的关系。例如:家谱,各种社会组织结构,操作系统中文件管理,编译程序中的语法树,数据库系统的数据组织方式等。直观上看,树形结构是以分支(父子)关系定义的层次结构。树型结构从上述定义中可以看到树结构具有如下特点:①有且仅有一个结点没有直接前驱结点,这个结点称为根结点;②除根结点外,其余所有结点有且仅有一个直接前驱结点;③每个结点都可以有多个(可以是0个)直接后继。树是一类重要的非线性数据结构,是以分支关系定义的层次结构树的定义定义定义:树(tree)是n(n0)个结点的有限集T,其中:有且仅有一个特定的结点,称为树的根(root)当n1时,其余结点可分为m(m0)个互不相交的有限集T1,T2,……Tm,其中每一个集合本身又是一棵树,称为根的子树(subtree)特点:树中至少有一个结点——根树中各子树是互不相交的集合A只有根结点的树ABCDEFGHIJKLM有子树的树根子树基本术语结点(node)——表示树中的元素,包括数据项及若干指向其子树的分支结点的度(degree)——结点拥有的子树数叶子(leaf)——度为0的结点孩子(child)——结点子树的根称为该结点的孩子双亲(parents)——孩子结点的上层结点叫该结点的~兄弟(sibling)——同一双亲的孩子堂兄弟()——双亲在同一层上的结点互为堂兄弟树的度——一棵树中最大的结点度数结点的层次(level)——从根结点算起,根为第一层,它的孩子为第二层……深度(depth)——树中结点的最大层次数森林(forest)——m(m0)棵互不相交的树的集合祖先(ancestors)——从根到该结点所经分支上的所有结点子孙(children)——以某结点为根的子树中的任一结点都称为该结点的子孙ABCDEFGHIJKLM结点A的度:3结点B的度:2结点M的度:0叶子:K,L,F,G,M,I,J结点A的孩子:B,C,D结点B的孩子:E,F结点I的双亲:D结点L的双亲:E结点B,C,D为兄弟结点K,L为兄弟树的度:3结点A的层次:1结点M的层次:4树的深度:4结点F,G为堂兄弟结点A是结点F,G的祖先树的表示通常树的表示方法有树形表示、嵌套集合表示、凹入表示和广义表表示四种,如下图所示:树的其它术语有时也引用家族树中的一些习惯用语,如孩子、双亲、祖先、子孙、兄弟等。如称结点的子树的根为该结点的孩子,该结点称为孩子的双亲;同一个双亲的孩子之间互称为兄弟;从结点向上到达根结点所途经的所有结点称为该结点的祖先,从结点向下所能到达的所有结点称为该结点的子孙。如右图中,A是B、C和D的双亲,B、C和D都是A的孩子,B、C和D三者之间互为兄弟;A和C是E的祖先,A的子孙是B、C、D、E和F。树的基本运算setnull(T):置T为空树,即初始化一棵树T。root(T)或root(x):求根函数。求树T的根或求结点x所在树的根结点,若T为空树或x不在树T中,则函数值为NULL。parent(T,x):求双亲函数。求树T中结点x的双亲结点,若x是树T的根结点或x不在树T中,则函数值为NULL。child(T,x,i):求孩子函数。求树T中结点x的第i个孩子结点,若结点x无第i个孩子则函数值为NULL。create(x,F):建树函数。生成一棵以x为根结点,以森林F为子树森林的树。rsibling(T,x):求右兄弟函数。求树T中结点x的右边兄弟,若x是其双亲的最右孩子或x不在T中,则函数值为NULL。树的基本运算(续)addchild(y,i,x):插入子树操作。把以结点x为根的树置为结点y的第i棵子树。若树中无结点y或它的子树个数小于i-1,则为空操作。delchild(x,i):删除子树操作。删除结点x的第i棵子树,若无结点x或x的子树个数小于i,则为空操作。traverse(T):遍历操作。按某个次序依次访问树中各个结点,并使每个结点只被访问一次。也就是说,遍历操作的结果是对非线性结构树中各结点,按某个次序给出一个线性化的结点序列。二叉树的概念二叉树是另一种重要的树型结构。它的特点是每个结点至多有两棵子树,即二叉树中任何结点的度不得大于2。二叉树的定义:二叉树(binarytree)是n(n≥0)个结点的有限集合,它或者(n=0时)为空树,或者(n>0时)由一个根结点及两棵互不相交的分别称为根的左子树和右子树的二叉树组成。二叉树的概念(续)由定义显见二叉树的递归性质。应该指出的是,二叉树与树是两个不同的概念,它不是树的特殊情况;这是因为二叉树的子树有左右之分,而树的子树不必区分次序。另外二叉树与度为2的有序树也是不同的概念;因为对于二叉树的子树而言,要么是根的左子树,要么是根的右子树,即使只有一棵子树也要区分是左是右;而度为2的有序树中,当一个结点有两棵子树时有左右之分,而只有一棵子树时就无左右之分。二叉树与度为2的普通树的区别举例在下图中,(a)和(b)所示的两棵二叉树虽然与(c)所示的普通树相似,但却不等同于这棵普通树。二叉树的五种基本形态二叉树可以是空树,根也可以有空的左子树、空的右子树或左右子树均为空,因此二叉树有五种基本形态,如下图所示:二叉树的基本运算树的术语对于二叉树都适用。与树的基本运算类似,二叉树也有如下的一些基本运算:求二叉树的根root(bt);求二叉树中结点x的双亲parent(bt,x);求二叉树中结点x的左孩子或右孩子lchild(bt,x)和rchild(bt,x);设置空二叉树setnull(bt);建立以x为根,以二叉树lbt和rbt为左右子树的一棵二叉树create(x,lbt,rbt);二叉树的基本运算(续)置以y为根的二叉树为结点x的左子树或右子树addlchild(bt,x,y)和addrchild(bt,x,y);删除结点x的左子树或右子树dellchild(bt,x)和delrchild(bt,x);在二叉树中查找结点x的运算search(bt,x);按照某种次序遍历二叉树中的所有结点traverse(bt)。二叉树的性质二叉树具有一些重要性质。性质1二叉树的第i(i≥1)层上至多有2i-1个结点。证明:用数学归纳法证明如下:当i=1时只有一个结点,2i-1=20=1,命题成立。设对于任意的j,1≤j<i时命题成立,即第j层上至多含有2j-1个结点。则由归纳假设第i-1层上至多含有2i-2个结点。由于二叉树中每个结点至多有两个孩子,故第i层上的最大结点数应为第i-1层上最大结点数的二倍,即2*2i-2=2i-1成立,故命题成立。二叉树的性质(续)性质2深度为k的二叉树至多有2k-1个结点(k≥1)。证明:深度为k的二叉树最多含有的结点数应是每层含有的最多结点数之和,由性质1应为20+21+…+2k-1=2k-1。性质3对任意一棵二叉树,若终端结点数为n,度为2的结点数为n2,则n0=n2+1。证明:设二叉树中度为1的结点数为n1,二叉树中总的结点数为n,则有n=n0+n1+n2再考虑孩子结点,除根结点之外的结点都是一个结点的孩子,二叉树中孩子结点总数为n-1;而度为1的结点有一个孩子,度为2的结点有两个孩子,因此二叉树中孩子结点的总数又为n1+2n2,即n-1=n1+2n2联立以上二等式可得n0=n2+1,原命题得证。二叉树的特殊形态——满二叉树满二叉树(fullbinarytree)是指深度为k且有2k-1个结点的二叉树。下图给出了深度为3的满二叉树。显然,满二叉树的每层含有结点数为最大值,不存在度为1的结点,除叶子结点外每个结点都有左右孩子,且叶子结点全部在第k层上。二叉树的特殊形态—完全二叉树完全二叉树(completebinarytree)是指深度为k的、有n个结点的二叉树,当且仅当它的每一个结点都与深度为k的满二叉树中编号从1到n的结点一一对应。下图给出了一棵深度为3的完全二叉树示例。显然,完全二叉树中前k-1层含有结点数为最大值,第k层不一定满但全部集中在左边而空缺留在右边,叶子结点只可能在第k层和第k-1层上出现。显而易见,满二叉树是完全二叉树的特殊情况,满二叉树一定是完全二叉树,反之不然。二叉树的性质(续)性质4具有n个结点的完全二叉树的深度为。证明:设该完全二叉树的深度为k,由完全二叉树的定义及性质2有2k-1-1<n≤2k-1,即有2k-1≤n<2k同时取对数后有k-1≤log2n<k因为k为整数,故有,即。二叉树的性质(续)性质5对于具有n个结点的完全二叉树,如果按照自上而下自左至右的顺序对所有结点从1到n编号,则对于任意的序号为i的结点有:如果i=1,则结点i是根结点,无双亲;如果i>1,则结点i的双亲结点编号为。如果2i<n,则结点i的左孩子编号为2i;否则无左孩子。如果2i+1<n,则结点i的右孩子编号为2i+1;否则无右孩子。如果i为奇数且不为1,则结点i的左兄弟编号为i-1;否则无左兄弟。如果i为偶数且小于n,则结点i的右兄弟编号为i+1;否则无右兄弟。二叉树的存储结构1顺序存储结构实现:按完全二叉树的结点层次编号,在数组中依次存放二叉树中的数据元素。特点:结点间关系蕴含在其存储位置中浪费空间,适于存储满二叉树和完全二叉树abcdefgabcde0000fg1234567891011定义如下:#defineMAXNODE最大结点数typedefstruct{datatypeSTree[MAXNODE];intlast;}SqBiTree;2二叉链表在每个结点中除存放数据元素的值以外,还设置了两个指针域lchild和rchild分别指向其左孩子和右孩子。在这2n个指针域中,只使用了n-1个,n+1个是空的。由于大多数操作都是从根开始的,所以设了一个指向根的指针来唯一标识一棵二叉树,称为根指针。typedefstructbtnode{elemtypedata;structbtnode*lchild,*rchild;}bitnode;typedefbitnode*bitree;lchilddatarchildABCDEFG在n个结点的二叉链表中,有n+1个空指针域ABCDEFG^^^^^^^^2二叉链表3三叉链表在二叉链表的基础上,在每个结点中增加了一个指向双亲的指针域,这样方便查找双亲,比较适合于经常访问双亲的情况。typedefstructnode{datatypedata;structnode*lchild,*rchild,*parent;}TriNode,*TriTree;lchilddataparentrchildABCDEFGABCDEFG^^^^^^^^^