目录
一.二叉树的定义
二叉树是另一种树形结构,其特点是每个结点至多作用两颗子树(即二叉树中不存在度定义2的结点),并且二叉树的子树有左右之分,其次序不可颠倒;与树相似,二叉树也已递归的形式定义。二叉树是n个(n>=0)个结点的有限集合。
- 空二叉树,n=0
- 有一个根结点和两个互不相交的被称为根的左子树和右子树组成。左子树和右子树分别是一颗二叉树
- 二叉树是有序树,左右子树颠倒,会变成新的二叉树
- 即使树中结点只有一颗子树,也要区分左右子树
二.二叉树的几种特殊形式
1.斜树
所有的结点都只有左子树的二叉树叫左斜树;所有结点都只有右子树的二叉树为右斜树。两者统称为斜树
2.满二叉树
一颗高度为h,且含2^h-1个结点的二叉树称为满二叉树,即树中的每一层都含有最多的结点。满二叉树的叶子结点都集中在二叉树的最下一层,并且除叶子结点之外的每个结点度数均为2。可以对满二叉树按层序编号:约定编号从根结点(根节点编号为A),自上而下,自左向右,这样,每个结点对应一个编号,对于编号为i的结点,若有双亲,则双亲为i/2,若有左孩子,则左孩子为2i;若有右孩子,则右孩子为2i+1
3.完全二叉树
高度为h,有n个结点的二叉树,当且仅当每个结点都与高度为h的满二叉树中编号为1~n的结点一一对应,称为完全二叉树
- 若i<n/2,则结点i为分支节点,否则为叶子结点
- 叶子结点只可能在层次最大的两层上出现,对于最大层次中的叶子结点,都依次排列在该层最左边的位置
- 若有度为1的结点,则只可能有一个,且该结点只有左孩子没有右孩子
- 按层序编号,一旦出现某个结点(i)为叶子结点或只有左孩子,则编号大于i的结点均为叶子结点
- 若n为奇数,则每个分支结点都有左孩子和右孩子;若为偶数,则编号最大的分支结点(n/2)只有左孩子,没有右孩子,其余分支结点左右孩子都有
4.二叉排序树
左孩子所有结点的关键字均小于根结点的关键字;右子树上所有的关键字均大于根结点的关键字;左子树和右子树又各是一颗二叉排序树
5.平衡二叉树
树上任意结点的左子树和右子树的深度之差不超过一
三.二叉树的性质
- 任意一棵树,若结点的数量为n,则边的数量为n-1
- 非空二叉树上的叶子结点树等于度为2的结点数加1,即n0=n2+1
- 非空二叉树上第k层上至多有2^k-1个结点(k>=1)
- 高度为h的二叉树至多有2^h-1个结点(h>=1)
- 对完全二叉树按从上到下,从左到右的顺序依次编号1,2,3……,n,所以:
- i>1时,结点i的双亲的编号为i/2,即当i为偶数时,它是双亲的左孩子;当i为奇数时,它是双亲的右孩子
- 当2i<=n时,结点的左孩子编号2i,否则无左孩子
- 当2i+1<=n时,结点i的右孩子编号为2i+1,否则无右孩子
- 结点i所在层次(深度)为{log2i}+1
6.具有n个(n>0)结点的完全二叉树的高度为{log2i}+1
四.二叉树的存储结构
1.顺序存储结构
二叉树的顺序存储是指用一组地址连续的存储单元依次自上而下,自左向右存储完全二叉树的结点元素,即将完全二叉树上编号为i的结点元素储存在一维数组下标为i-1的分量中。依据二叉树的性质,完全二叉树和满二叉树才用顺序存储比较合适,树中结点的序号可以唯一地反映结点之间的逻辑关系,这样即能最大可能地节省存储空间,又能利用数组元素的下标值确定结点在二叉树中的位置,以及结点之间的关系。
但对于一般的二叉树,为了让数组下标能反映二叉树中结点之间的逻辑关系,只能添加一些并不存在的空节点,让其每个结点与完全二叉树上的结点相互对照,再存储到一维数组的相对应分量中,然而,在最坏情况下,一个高度为h且只有h个结点的单枝树却需要占据2h-1个存储单元。
2.链式存储结构
顺序存储适应性不强,就需要考虑链式存储结构。二叉树每个结点最多有两个孩子,所有要有一个数据域,两个指针域,这样的链表称为二叉链表
lchild | data | rchild |
其中lchild为左孩子指针,rchild为右孩子指针
typedef struct BiTNode
{
ElemType data;
struct BiTNode *lchild,*rchild;
} BiTNode,*BiTree;
五.二叉树的遍历
二叉树的遍历是指从根节点出发,按照某个次序访问二叉树中所有结点,使得某个结点被依次访问一次且仅访问一次
先序遍历
根节点—>左子树—>右子树
void InOrder(BiTree T)
{
if(!T)
{
visit(T->data);
InOrder(T->lchild);
InOrder(T->rchild);
}
}
中序遍历
左子树—>根节点—>右子树
void InOrder(BiTree T)
{
if(!T)
{
InOrder(T->lchild);
visit(T->data);
InOrder(T->rchild);
}
}
后序遍历
左子树—>右子树—>根节点
void InOrder(BiTree T)
{
if(!T)
{
InOrder(T->lchild);
InOrder(T->rchild);visit(T->data);
}
}