概述
二叉树是树的特殊一种,具有如下特点:
- 每个结点最多有两颗子树,结点的度最大为2。
- 左子树和右子树是有顺序的,次序不能颠倒。
- 即使某结点只有一个子树,也要区分左右子树。
二叉树五种基本形态
- 空二叉树。
- 只有一个根结点。
- 根结点只有左子树。
- 根结点只有右子树。
- 根结点既有左子树又有右子树。
特殊二叉树
斜树
- 斜树一定要是斜的,但是往哪斜还是有讲究。所有的结点都只有左子树的二叉树叫左斜树。所有结点都是只有右子树的二叉树叫右斜树。这两者统称为斜树 。
- 斜树有很明显的特点,就是每 一层都只有一个结点,结点的个数与二叉树的深度相同 。
满二叉树
- 在一棵二叉树中,如果所有分支结点都存在左子树和右子树,并且所有叶子都在同一层上,这样的二叉树称为满二叉树
- 单是每个结点都存在左右子树,不能算是满二叉树,还必须要所有的叶子都在同一层上,这就做到了整棵树的平衡
完全二叉树
- 对一棵具有n个结点的二叉树按层序编号,如果编号为
i
的结点与同样深度的满二叉树中编号为i的结点在二叉树中位置完全相同,则这棵二叉树称为完全二叉树
满二叉树一定是一棵完全二叉树,但完全二叉树不一定是满的 。
完全二叉树的所有结点与同样深度的满二叉树,它们按层序编号相同的结点是一 一对应的
- 像图 6-5-7 中的树 1,因为5结点 没有左子树,却有右子树,那就使得按层序编号的第 10 个编号空档了。
- 同样道理,图 6-5-7 中的树2,由于3结点没有子树,所以使得 6、7 编号的位置空挡了。
- 图 6-5-7 中的树3又是因为5编号下没有子树造成第 10 和第 11 位置空档。
- 只有图 6-5-6 中的 树,尽管它不是满二叉树,但是编号是连续的,所以它是完全二叉树。
完全二叉树的特点:
- 叶子结点只能出现在最下两层。
- 最下层的叶子一定集中在左部连续位置。
- 倒数二层,若有叶子结点,一定都在右部连续位置。
- 如果结点度为 1,则该结点只有左孩子,即不存在只有右子树的情况。 同样结点数的二叉树,完全二叉树的深度最小。
二叉树的性质
在二叉树的第i层上至多有2的i-1次方个结点.
深度为k的二叉树至多有2的k次方减1个结点($2^k-1$)。
对任何一棵二叉树 T,如果其终端结点数为$n_0$,度为2的结点数为$n_2$,则$n_0$=$n_2$+1
比如图 6-6-1 的例子,结点总数为 10,宫是由 A、 B、 c、 D 等度为 2 结点, F、 G、H、 l、J等度为0的叶子结点和E这个度为1的结点组成。 总和为4+1+5=10。
具有 n 个结点的完全二叉树的深度为[logn2n]+1
如果对一棵有 n 个结点的完全二叉树(其深度为 [logn2n]+1) 的结点按层 序编号(从第 1 层到第[logn2n]+1层,每层从左到右),对任一结点 i (1<=i<=n) 有:
- 如果
i=1
,则结点 i 是二叉树的棍,无双亲;如果i> 1,则其双亲是结点 $\frac{i}{2}$。 - 如果
2*i>n
,则结点 i 左孩子(结点i为叶子结点) ;否则其左孩子是结点2*i。 - 如果
2*i+1>0
,则结点i无右孩子;否则其右孩子是结点2*i+1
.
- i=l 时就是根结点。 i>1 时,比如结点7的双亲就是7/2=3, 结点9它的双亲就是9/2=4
- 第二条, 比如结点 6,因为 2X6=12 超过了结点总数 10,所以结点 6 元左孩子 , 它是叶子结点。 同样,而结点5, 因为2XS=10正好是结点,总数10,所以它的左孩子 是结点 10。
- 第三条,比如结点 5,因为 2X5+1=l1,大于结点总数 10,所以它无右孩子。 而 结点 3,因为 2X3吐=7小于 10,所以宫的右孩子是结点 7
二叉树的顺序存储结构
- 二叉树的顺序存储结构就是用一维数组存储二叉树中的结点,井且结点的存储位
置,也就是数组的下标要能体现结点之间的逻辑关系,比如双亲与孩子的关系,左右 兄弟的关系等。 - 顺序存储 结构一般只用于完全二叉树。
1 | package com.example.qxw.tree; |
二叉树的链式存储结构
- 二叉树每个结点最多有 两个孩子,所以为它设计一个数据域和两个指针域是 比较自然的想法, 我们称这样的 链表叫做二叉链衰
data是数据区域。lchild和 民rchild都是指针域分别存放指向左孩子和右孩子的指针
遍历二叉树
- 二叉树的遍历是指从根结点出发,按照某种次序依次访问二叉树中所有结点.使得每个结点被访问-次 旦仅被访问一次 。
- 二叉树的遍历次序不同于线性结构,最多也就是从头至尾、循环、双向等简单的 遍历方式。树的结点之间不存在唯一的前驱和后继关系,在访问 一个结点后,下一个 被访问的结点面临着不同的选择 。
二叉树遍历方法
如果我们限制了从左到右的习惯方式,那么主要就分为四种
- 前序遍历
- 若二叉树为空,则空操作返回,否则先访问根结点,然后前序遍历左子 树 , 再前序遍历右子树
- 中序遍历
- 若树为空,则空操作返回,否则从根结点开始(注意并不是先访问根结点),中序遍历根结点的左子树,然后是访问根结点,最后中序遍历右子树 。
- 后序遍历
- 若树为空,则空操作返回,否则从左到右先叶子后结点的方式遍历访问左右子树,最后是访问根结点
- 层序遍历
- 若树为空,则空操作返回,否则从树的第一层,也就是根结点开始访问, 从上而下逐层遍历,在同一层中, 按从左到右的颇用才结点逐个访问
JAVA实现二叉树的链式存储以及遍历
1 | public class TreeNode<E> { |