二叉树
二叉树也称二分树,是有限的节点集合,这个集合或者是空,或者是由一个根节点和两棵互不相交的称为左子树和右子树的二叉树组成。
二叉树结构简单,存储效率高,运算算法也相对简单,而且任何m次树都可以转化为二叉树结构。因此二叉树具有很重要的地位。
二叉树和2次树的区别,对于非空树:1、二次树中至少有一个节点的度为2,二叉树没有此要求2、二次树不区分左、右子树,二叉树严格区分左、右子树。
二叉树5种基本形态:1.空二叉树2.单节点二叉树3.右子树为空的二叉树4.左子树为空的二叉树5.左右子树都不为空的二叉树。
二叉树ADT、表示方法、术语均与树一致。
在一棵二叉树中,如果所有分支节点都有左孩子节点和右孩子节点,并且叶子节点都集中在二叉树的最下一层,这样的二叉树称为满二叉树。或一颗高度为h且有2h-1个节点的二叉树称为满二叉树。可以对二叉树的节点进行层序编号,约定编号从树根为1开始,按层数从小到大,同一层从左到右的次序进行。
满二叉树特点:叶子节点都在最下一层;只有度为0和度为2的节点。
若二叉树中最多只有最下面两层的节点的度小于2,并且最下面一层的叶子节点都依次排列在该层最左边的位置上,则这样的二叉树称为完全二叉树。满二叉树是完全二叉树的特例。
完全二叉树特点:
- 叶子节点只可能在层次最大的两层上出现
- 对于最大层次中的叶子节点,都依次排列在该层最左边的位置上
- 若有度为1的节点,只可能有一个,且该节点只有左孩子而无右孩子
- 按层序编号后,一旦出现某编号为i的节点,为叶子节点或只有左孩子,则编号大于i的节点均为叶子节点
- 当节点总数n为奇数时,度为1的节点个数n1=0,当节点总数n为偶数时,n1=1
二叉树性质:
- 非空二叉树上叶子节点数等于双分支节点数加1
- 非空二叉树上第i层上至多有2i-1个节点(i≥1)
- 高度为h的二叉树至多有2h-1个节点(h≥1)
- 对完全二叉树中编号为i的节点(1≤i≤n,n≥1,n为节点数)有:
- 若i≤(n/2)向下取整(即2i≤n),则编号为i的节点为分支节点,否则为叶子节点。
- 若n为奇数,则没有单分支节点,若为偶数,则编号最大的分支节点(n/2)只有左孩子节点,没有右孩子节点。
- 若编号为i的节点有左孩子节点,则左孩子节点的编号为2i;若编号为i的节点有右孩子节点,则右孩子节点的编号为2i+1。
- 除树根节点外,若一个节点的编号为i,则它的双亲节点的编号为i/2向下取整。
- 具有n个(n>0)节点的完全二叉树的高度为log2(n+1)向上取整,或log2(n)向下取整+1
二叉树与树、森林之间的转化:树、森林与二叉树之间有一个自然的对应关系,它们之间可以进行相互转换。因此可以把树中处理的问题对应到二叉树中进行处理,从而使问题简单化。由于树中节点左右次序无关紧要,但二叉树左右孩子节点不能随意颠倒,因此把一般树作为有序树来处理,以免引起混乱。
森林、树转换为二叉树:
若森林T={T1,T2,…,Tm}是m(m≥0)棵树的序列,则与T相对应的二叉树β(T)的构造方法如下:
- 如果m=0,则β(T)为空二叉树。
- 如果m>0,则β(T)的根节点为T1的根节点,β(T)根节点的左子树为β(T1,1,T1,2,…, T1,r),其中T1,1,T1,2,…, T1,r是T1的子树;β(T)根节点的右子树为β(T2,T3,…,Tm)。
此方法是一种递归构造方法,如果假定T是有序树的序列,那么由T所构造的二叉树β(T)是唯一的。
该方法构造的二叉树β(T)的节点与原来树T的节点的关系为:二叉树β(T)的任意节点k,若有左孩子节点,则该左孩子节点为k原来的最左边(第一棵)子树的根节点;若有右孩子字节,则该右孩子节点为k原来的右边相邻的第一个兄弟节点或右边第一棵相邻的树的根节点(当k为原森林中树的根节点时)。由此可以把递归构造二叉树β(T)的过程归纳如下:
- 在所有相邻兄弟节点(森林中每棵树的根节点可看成是兄弟节点)之间加一条水平连线。
- 对每个非叶子节点k,除了其最左边的孩子节点外,删去k与其他孩子节点的连线。
- 所有水平线段以左边节点为轴心顺时针旋转45°。
通过以上步骤,原来的森林就转换为一棵二叉树。一棵树是森林中的特殊情况,由一棵树转换的二叉树的根节点的右孩子节点始终为空,原因是一棵树的根节点不存在兄弟节点和相邻的树。
二叉树中左孩子节点表示原先树中的孩子关系,右孩子节点表示兄弟关系。
二叉树还原为森林、树:
若β(T)是一棵二叉树,把β(T)还原为相对应的m(m≥0)棵树序列构成的森林T={T1,T2,…,Tm}的方法如下:
- 如果β(T)为空二叉树,则T为空(m=0)。
- 如果β(T)为非空二叉树,则T中的第一棵树T1的根节点为β(T)的根节点;T1中根节点的子树序列{ T1,1,T1,2,…, T1,r }是由β(T)左子树还原而成的森林;T中除T1外的其余树组成的序列{ T2,T3,…,Tm }是由β(T)右子树还原而成的森林。
将由森林或一棵树转换而来的二叉树还原为森林或一棵树的过程如下:
- 对于一棵二叉树中任一节点k1,沿着k1右孩子节点的右子树方向搜索所有右孩子结点,即搜索节点序列k2,k3,…,km,其中ki+1为ki的右孩子节点(1≤i<m),km没有右孩子节点。
- 删去k1,k2,…,km,之间的连线。
- 若k1有双亲节点k,则连接k与ki(2≤i≤m)。
- 将图形规整化,使各节点按层次排列。
若二叉树根节点有m个右孩子节点,则还原成森林时有m+1棵树。
二叉树存储结构:
二叉树的存储结构主要有顺序存储结构和链式存储结构两种。
顺序存储结构:用一组地址连续的存储单元来存放二叉树的数据元素。
因此必须确定好树中各数据元素的存放次序,使得各数据元素的相互位置能反映出数据元素之间的逻辑关系。
存放次序是:对该树中每个节点进行编号,其编号从小到大的顺序就是节点存放在连续存储单元的先后次序。若把二叉树存储到一维数组中,则该编号就是下标值加1(当数组的起始下标为0)。树中各节点的编号与等高度的完全二叉树中对应位置上节点的编号相同。其编号过程是:首先把树根节点的编号定为1,然后按照从上到下、从左到右的顺序,对每一节点进行编号。当某节点是编号为i的双亲节点的左孩子节点时,则它的编号应为2i;当它是右孩子节点时,则它的编号应为2i+1。
根据二叉树性质,访问二叉树的双亲节点和左右孩子节点都非常方便。
顺序结构类型定义如下:typedef Elemtype SqBTree[MaxSize];
其中ElemType为二叉树中节点值的类型,当二叉树中某节点为空节点或无效节点(不存在该编号的节点)时,对应位置的值用特殊值(“#”)表示。
顺序存储结构适用于完全二叉树,对于退化的二叉树(每个分支节点都是单分支的),空间浪费十分严重,且插入删除等运算十分不方便。
链式存储结构(二叉链):用一个链表来存储一棵二叉树,二叉树中每一个节点用链表中一个链节点来存储。节点结构:lchild data rchild
其中data表示值域,用于存储节点的数据元素,lchild和rchild分别表示左指针域和右指针域,分别用于存储左孩子节点和右孩子节点的存储位置。
二叉树基本运算:创建,按值查找节点,查找孩子节点,求高度,输出
二叉树遍历:二叉树遍历是指按照一定次序访问二叉树中所有节点,并且每个节点仅访问一次的过程,它是最基本的运算,是二叉树中所有其他运算的基础。
先序遍历过程:访问根节点,先序遍历左子树,先序遍历右子树。
中序遍历过程:中序遍历左子树,访问根节点,中序遍历右子树。
后序遍历过程:后序遍历左子树,后序遍历右子树,访问根节点。
层次遍历过程:访问根节点(第1层),从左到右访问第2层所有节点,至最后一层访问完。
二叉树构造:假设二叉树中每个节点的值均不相同,同一棵二叉树具有唯一的先序序列、中序序列和后序序列,但不同的二叉树可能具有相同的先序序列、中序序列、后序序列。显然,仅由一个先序(中序、后序)序列,无法确定这棵二叉树的树形。但若知道先序、中序或者中序、后序序列,即可确定该树树形。同时知道先序和后序无法确定树形。
定理1:任何n(n≥0)个不同节点的二叉树,都可由它的中序序列和先序序列唯一确定。
实际上,先序序列作用是确定一棵二叉树的根节点(其第一个元素即为根节点),中序序列的作用是确定左、右子树的中序序列(包括确定其各自的节点个数),进而确定左、右子树的先序序列。
定理2:任何n(n≥0)个不同节点的二叉树,都可由它的中序序列和后序序列唯一确定。