1. 二叉树的定义
概念: 二叉树是 n(n >= 0)个结点的有限集合,该集合由一个根结点和两颗互不相交的,分别称为根结点的左子树和右子树的二叉树组成。
二叉树的特点
- 每个结点最多有两颗子树,所以二叉树中不存在度大于 2 的结点;
- 左子树和右子树是有顺序的,次序不能任意颠倒;
- 即使树中某结点只有一棵子树,也要区分它是左子树还是右子树;
斜树
概念: 所有的结点都只有 左子树 或者 右子树 的二叉树称为斜树。
满二叉树
概念: 所有分支结点都存在左子树和右子树,并且所有叶子都在同一层上,这样的二叉树称为满二叉树
完全二叉树
对一颗具有 n 个结点的二叉树按层序编号,如果编号为 i (1 <= i <= n )的结点与同样深度的满二叉树中编号为 i 的结点中位置完全相同,则这颗二叉树称为完全二叉树
完全二叉树的一些特点
- 叶子结点只能出现在最下两层;
- 最下层的叶子一定集中在左部连续位置;
- 倒数二层,若有叶子结点,一定都在右部连续位置;
- 如果结点度为 1 ,则该结点只有左孩子,即不存在只有右子树的情况;
- 同样结点树的二叉树,完全二叉树的深度最小;
2. 二叉树的存储结构
二叉树的 链式存储结构 适用性更为普遍,二叉树每个结点最后有两个孩子,所以为它设计一个数据域和两个指针域,我们称之为 二叉链表
typedef struct BiTNode{ // 树结点的数据类型
int data; // 结点数据
struct BiTNode *lchild, *rchild;
}BiTNode, *BiTree;
3. 遍历二叉树
二叉树的遍历是指从根结点出发,按照某种 次序 依次访问二叉树中所有结点,使得每个结点仅且被访问一次。
前序遍历
若二叉树为空,则空操作返回,否则先访问根结点,然后前序遍历左子树,再前序遍历右子树。如下图所示,遍历顺序为:ABDGHCEIF
/* 采用递归算法 */
void PreOrderTraverse(BiTree T)
{
if(T == nullptr)
return;
cout << T->data; // 先访问根结点,显示结点数据
PreOrderTraverse(T->lchild); // 然后 遍历左子树
PreOrderTraverse(T->rchild); // 最后 遍历右子树
}
中序遍历
若树为空,则空操作返回,否则从根结点开始(注意并不是访问根结点),中序遍历根结点的左子树,然后是访问根结点,最后中序遍历右子树。如下图所示,遍历顺序为:GDHBAEICF
/* 二叉树的中序遍历递归算法 */
void InOrderTraverse(BiTree T)
{
if (T == nullptr)
return;
InOrderTraverse(T->lchild); // 中序遍历根结点的左子树
cout << T->data << endl; // 然后是访问根结点,显示结点数据
InOrderTraverse(T->rchild); // 最后中序遍历右子树
}
后序遍历
若树为空,则空操作返回,否则从左到右先叶子后结点遍历访问左右子树,最后是访问根结点。如下图所示,遍历顺序为:GHDBIEFCA
/* 二叉树的后续遍历递归算法 */
// 从左到右先叶子后结点,遍历访问左右子树,最后是访问根结点
void PostOrderTraverse(BiTree T)
{
if(T == nullptr)
return;
PostOrderTraverse(T->lchild); // 后序遍历的左子树
PostOrderTraverse(T->rchild); // 后序遍历右子树
cout << T->data << endl; // 然后是访问根结点,显示结点数据
}
层序遍历
若树为空,则空操作返回,否则从树的第一层,也就是根结点开始访问,从上而下逐层遍历。如下图所示,遍历顺序为:ABCDEFGHI
遍历二叉树的性质–非常重要
- 已知前序遍历序列和中序遍历序列,可以唯一确定一棵二叉树
- 已知后序遍历序列和中序遍历序列,可以唯一确定一棵二叉树
例1:已知一棵二叉树的前序序列为 ABCDEF,中序序列为 CBAEDF,则这颗二叉树的后续遍历结果为:CBEFDA
例2:已知一棵二叉树的中序序列是 ABCDEFG,后序序列是BDCAFGE,则这颗二叉树的前序遍历结果为:EACBDGF
参考内容:《大话数据结构-大话设计模式》-- 程杰