二叉树的定义
二叉树(BinaryTree)是n(n≥0)个结点的有限集,它或者是空集(n=0),或者由一个根结点及两棵互不相交的、分别称作这个根的左子树和右子树的二叉树组成。这个定义是递归的。由于左、右子树也是二叉树, 因此子树也可为空树。共有五种不同基本形态的二叉树。
注意:二叉树与度数为2的有序树不同,在有序树中,虽然一个结点的孩子之间是有左右次序的,但是若该结点只有一个孩子,就无须区分其左右次序。而在二叉树中,即使是一个孩子也有左右之分。
二叉树的性质
二叉树具有以下重要性质:
性质1 二叉树第i层上的结点数目最多为2^(i-1)(i≥1)。
证明:用数学归纳法证明:
归纳基础:i=1时,有2^(i-1)=2^0=1。因为第1层上只有一个根结点,所以命题成立。
归纳假设:假设对所有的j(1≤j<i)命题成立,即第j层上至多有2^(j-1)个结点,证明j=i时命题亦成立。
归纳步骤:根据归纳假设,第i-1层上至多有2^(i-2)个结点。由于二叉树的每个结点至多有两个孩子,故第i层上的结点数至多是第i-1层上的最大结点数的2倍。即j=i时,该层上至多有2&2^(i-2)=2^(i-1)个结点,故命题成立。
性质2 深度为k的二叉树至多有2^k-1个结点(k≥1)。
证明:由性质 (1) 可知各层结点最多数目之和为: 2^0 + 2^1 + 2^2 +.....+ 2^(k-1) ;由二进制换算关系可知: 2^0 + 2^1 + 2^2 +.....+ 2^(k-1) = 2^k - 1 ;因此二叉树树中结点的最大数目为 2^k - 1 。性质2证明完毕。
性质3 在任意一棵二叉树中,若叶子结点(即度为0的结点)的个数为n0,度为1的结点数为n1,度为2的结点数为n2,则no=n2+1。
证明:因为二叉树中所有结点的度数均不大于2,所以结点总数(记为n)应等于0度结点数、1度结点(记为n1)和2度结点数之和:n=no+n1+n2;由于有n个结点的二叉树总边数为n-1条,于是得:n-1=0n0+1n1+2*n2;代入得:n0=n2+1。性质3证明完毕。
性质4 具有n个结点的完全二叉树树深为[log2n]+1,其中[log2n]+1是向下取整。
证明:假设某完全二叉树的结点总数是 n ,它的值应该大于树深为 k-1 的满二叉树结点数 2 ^(k-1 - 1) ,小于等于树深为 k 的满二叉树结点数 2^(k-1) 。
2^(k-1 -1) < n <= 2^(k-1)
由于该不等式各项均为整数,当对两端两项各加 1 时不等式发生变化得:
2^(k-1) <= n < 2^k
再对其取对数得: k-1<= [log2n] < k
如果对 [log2n] 取整显然等于 k-1,所以得:k =[log2n] + 1,性质4证明完毕。
**性质5 若对有 n 个结点的完全二叉树进行顺序编号 (1 ≤ i ≤ n) ,那么: **
对于编号为 i(i ≥ 1) 结点 :
当 i=1 时,该结点为根,它无双亲结点;
当 i>1 时,该结点的双亲结点编号为 [i/2];
若 2i ≤ n ,它有编号为 2i 的左孩子,否则没有左孩子;
若 2i+1 ≤ n ,则它有编号为 2i+1 的右孩子,否则没有右孩子。
看到网上有个题目:一棵完全二叉树有770个节点,问它的叶子节点有多少个?
计算树的深度:[log2n]+1向下取整得出树深k=11;
计算最后一层的节点数:770-2^(11-1 - 1)=258;
计算倒数第二层的叶子节点数:(512-258)/2=127;
所以总的叶子节点数:258+127=385.
满二叉树和完全二叉树
满二叉树(FullBinaryTree)
一棵深度为k且有2k-1个结点的二又树称为满二叉树。满二叉树的特点:
- 每一层上的结点数都达到最大值。即对给定的高度,它是具有最多结点数的二叉树。
- 满二叉树中不存在度数为1的结点,每个分支结点均有两棵高度相同的子树,且树叶都在最下一层上。
完全二叉树(Complete BinaryTree)
若一棵二叉树至多只有最下面的两层上结点的度数可以小于2,并且最下一层上的结点都集中在该层最左边的若干位置上,则此二叉树称为完全二叉树。完全二叉树特点:
- 满二叉树是完全二叉树,完全二叉树不一定是满二叉树。
- 在满二叉树的最下一层上,从最右边开始连续删去若干结点后得到的二叉树仍然是一棵完全二叉树。
- 在完全二叉树中,若某个结点没有左孩子,则它一定没有右孩子,即该结点必是叶结点。
二叉树的存储方式
顺序存储表示
一般采用数组或线性表实现,对于完全二叉树该存储方式不会浪费存储控件。(不是所有的树都是完全二叉树,所以...)
二叉链表表示
class BitNode{
T data ;
BitNode lc ;
BitNode rc ;
}
三叉链表表示
改进的二叉链表,添加了指向父节点的地址。避免了在找回父节点时需要重新遍历的问题。
class BitPNode{
T data ;
BitPNode lc ;
BitPNode rc ;
BitPNode p ;
}