二叉树是一种特殊的树结构,也是常用的树结构。二叉树的存储和处理比一般的树简单,同时一般的树都能通过简单的转换得到与之对应的二叉树,这样就可以采用二叉树的存储结构和有关算法来解决树的有关问题。
二叉树与树一样具有递归性质,它与树的区别主要有以下两点:
1)二叉树的每个结点至多只有两棵子树(即二叉树中不存在度大于2的结点)
2)二叉树的子树有左右之分,其次序不能任意颠倒。二、二叉树的性质
性质1 在二叉树的第i层上至多有2^(i-1)个结点(i>=1)
性质2 深度为k的二叉树至多有2^k-1个结点
性质3 对任何一颗二叉树T,如果其终端结点数位n0,度为2的结点数位n2,则n0=n2+1;
因为二叉树中所有结点的度均小于或等于2,所以其结点总数为 n=n0+n1+n2;
除了根结点外,其余结点都有一个分支进入,设B为分支总是,则n=B+1;由于这些分支都是由度为1或2的结点射出的,所以又有B=n1+2n2,所以 n=n1+2n2+1 -> n0=n2+1
两种特殊形态的二叉树,它们是满二叉树和完全二叉树。
满二叉树:深度为k且含有2^k-1个结点的二叉树
满二叉树的特点是:每一层上的结点数都是最大结点数,即每一层i的结点数都具有最大值2^(i-1)可以对满二叉树的结点进行连续编号,约定编号从根结点起,自上而下,自左至右。由此可以引出完全二叉树的定义。
完全二叉树:深度为k的,有n个结点的二叉树,当且仅当其每一个结点都与深度为k的满二叉树中编号从1至n的结点一一对应时,称之为完全二叉树。
完全二叉树的特点是:
1)叶子结点只可能在层次最大的两层上出现
2)对任一结点,若其右分支下的子孙的最大层次为l,则其左分支下的子孙的最大层次必为l或l+1.
性质4和性质5是完全二叉树的两个重要特性
性质4 具有n个结点的完全二叉树深度为[log2(n)]+1(不大于log2(n)的最大整数);
根据性质2和完全二叉树的定义有
2^(k-1)-1<n<=2^k-1 或 2^(k-1)<=n<2^k
于是k-1 <= log2n < k;
性质5 如果对一棵有n个结点的完全二叉树(其深度为[log2(n)]+1)的结点按层序编号(从第1层到第[log2(n)]+1层,每层从左到右),则对任一结点i(1<=i<=n),有
1)如果i = 1,则结点i是二叉树的根,无双亲;如果i > 1,则其双亲PARENT(i)是[i/2].
2)如果2i > n,则结点i无左孩子(结点i为叶子结点);否则其左孩子LCHILD(i)是结点2i;
3)如果2i+1 > n,则结点i无右孩子;否则其右孩子RCHILD(i)是结点2i+1.三、二叉树的存储结构
1.顺序存储结构
二叉树的顺序存储表示:
#define MAXTSIZE 100 /*二叉树的最大结点数*/
typedef TElemType SqBiTree[MAXTSIZE];
SqBiTree bt;
这种顺序存储结构仅适用于完全二叉树。
2.链式存储结构
因为用顺序存储结构可能会造成存储空间的极大浪费,对于一般二叉树更适合采用链式存储结构。
由二叉树的定义,二叉树的结点由一个数据元素和分别指向其左、右子树的两个分支构成,则表示二叉树的链表中的结点至少包含3个域:数据域和左、右指针域。
有时,为了方便找到结点的双亲,还可在结点结构中增加一个指向其双亲结点的指针域。利用这两种结点结构所得二叉树的存储结构分别称之为二叉链表和三叉链表。
在含有n个结点的二叉链表中有n+1个空链域。因为在n个结点的二叉链表中,必有2n个链域。除根结点外,每个结点有且仅有一个双亲的,所以只会有n-1个结点的链域存放指针,空指针数目 = 2n-(n-1) = n+1;
可以利用这些空链域存储其他有用信息,从而得到另一种链式存储结构——线索链表
二叉树的二叉链表存储表示:
typedef struct BiTNode
{
TElemType data; /*结点数据域*/
struct BiTNode *lchild,*rchild; /*左右孩子指针*/
}BiTNode,*BiTree;
二叉树的三叉链表存储表示:
typedef struct TriTNode
{
TElemType data; /*结点数据域*/
struct TriTNode *lchild,*parent,*rchild /*多了个双亲指针*/
}TriTNode,*TriTree;