二叉树

原文地址:https://wanqbin.xyz/2019/07/30/二叉树/

一、二叉树的定义

 二叉树(Binary Tree)是n(n>=0)个有限结点构成的集合。n=0的树称为空二叉树;n>0的二叉树由一个根节点和两个互不相交、分别称作左子树和右子树的子二叉树构成。

 二叉树是一种有序树。二叉树中某个结点即使只有一个子树,也要区分是左子树还是右子树。

 二叉树中所有结点的形态共有5种:空结点、无左右子树结点、只有左子树结点、只有右子树结点和左右子树均存在的结点。

 满二叉树。在一棵二叉树中,如果所有分支结点都存在左子树和右子树,并且所有叶子结点在同一层上,这样的二叉树称为满二叉树

 完全二叉树。如果一棵具有n个结点的二叉树的结构与满二叉树的前n个结点的结构相同,这样的二叉树称为完全二叉树。

二、二叉树的性质

  • 性质1:若规定根结点的层次为0,则一棵非空二叉树的第i层上最多有 2 i 2^i 2i(i>=0)个结点。
  • 性质2:若规定空树的深度为-1,则深度为k的二叉树的最大结点数是 2 k + 1 − 1 2^{k+1}-1 2k+11(k>=-1)个。
  • 性质3:对于一棵非空的二叉树,如果叶节点的个数为 n 0 n_0 n0,度为2的结点数为 n 2 n_2 n2,则有 n 0 = n 2 + 1 n_0=n_2+1 n0=n2+1.
  • 性质4:对于具有n个结点的完全二叉树,如果按照从上至下和从左至右的顺序对所有结点从0开始顺序编号,则对于任意的序号为i的结点,有:
    1. 如果i>0,则序号为i结点的双亲结点的序号为(i-1)/2,如果i=0,则序号为i的结点为根结点,无双亲结点。
    2. 如果2i+1=n,则序号为i结点无左孩子。
    3. 如果2i+2=n,则序号为i的结点无右孩子。

三、二叉树的操作

 二叉树是由一个根结点和两个互不相交的、分别称为左子树和右子树的子二叉树构成。因此,二叉树的操作和树的操作多数及基本类同,只在子树操作上略有不同。

 二叉树的操作也分为三类:第一类,找满足某种特定关系的结点;第二类,插入或删除某个结点;第三类,遍历树中每个结点。

  1. 第一类操作
    • 寻找根结点使之成为当前结点
    • 寻找当前结点的双亲结点使之成为当前结点
    • 寻找当前结点的左孩子结点使之成为当前结点
    • 寻找当前结点的右孩子结点使之成为当前结点
  2. 第二类操作
    • 在二叉树的当前结点上插入一个新结点,使新插入的节点称为当前结点的左孩子结点
    • 在二叉树的当前结点上插入一个新结点,使新插入结点成为当前结点的右孩子结点
    • 在二叉树的当前结点插入一个新子树,使新插入子树称为当前结点的左子树
    • 在二叉树的当前结点插入一个新子树,使新插入子树称为当前结点的右子树
    • 删除二叉树的当前结点的左孩子结点
    • 删除二叉树的当前结点的右孩子结点
    • 删除二叉树的当前结点的左子树
    • 删除二叉树的当前结点的右子树
  3. 第三类操作
    • 按某种方式遍历一棵二叉树显示二叉树中每个结点的数据域值
    • 按某种方式遍历一棵二叉树寻找数据元素域为某一值的结点
    • 先序遍历(DLR)递归算法
      • 访问根结点
      • 前序遍历根结点的左子树
      • 前序遍历根结点的右子树
    • 中序遍历(LDR)递归算法
      • 中序遍历根结点的左子树
      • 访问根结点
      • 中序遍历根结点的右子树
    • 后序遍历(LRD)递归算法
      • 后序遍历根结点的左子树
      • 后序遍历根结点的右子树
      • 访问根结点
    • 二叉树还有层序遍历。二叉树的层序遍历要求按照从根结点至叶结点、从左子树至右子树的次序访问二叉树的结点。二叉树的层序遍历算法为:
      • 初始化设置一个队列,并把根结点加入队列
      • 当队列非空时,循环下面注明的步骤③到步骤⑤;否则到步骤⑥
      • 出队列取得一个结点,访问该结点的(步骤③)
      • 若该结点的左子树非空,则将该结点的左子树入队列
      • 若该结点的右子树非空,则将该结点的右子树入队列(步骤⑤)
      • 结束。

四、二叉树的存储结构

 二叉树的存储结构主要有三种:顺序存储结构、链式存储结构和仿真指针存储结构。

  1. 二叉树的顺序存储结构

     对于一般的二叉树,如果按从上至下和从左至右的次序存储在一组从0开始的连续内存单元中,则数据下标之间的关系就不能反映二叉树中结点之间的逻辑关系。此时,可在一般二叉树中增添一些并不存在的空结点使之变成完全二叉树的形态,然后再用二叉树的顺序存储结构存储。

     完全二叉树使用顺序存储结构存储时,既能节省存储空间,又能使二叉树的操作实现简单。但对于一般二叉树,如果它接近于完全二叉树,需要增加的空结点数目不多时,可采用顺序存储结构存储。但如果需要增加许多空结点时,就不宜采用顺序存储结构存储。最坏的情况是右单只树,一棵深度为k的右单只树只有k个结点,却需分配 2 k 2^k 2k-1个存储单元。

  2. 二叉树的链式存储结构

     二叉树的链式存储结构方式用指针建立二叉树中结点之间的关系。二叉树最常用的链式存储结构是二叉链。二叉链存储结构的每个结点包含三个域:数据域data,左子树指针域leftChild和右子树指针域rightChild

     二叉树的二叉链存储结构是一种常用的二叉树存储结构。二叉链存储结构的优点是:结构简单,可以方便地构造任意需要的二叉树,可以方便地实现二叉树操作中的大多数操作。二叉链仓促结构的缺点是查找当前结点的双亲结点操作实现起来比较麻烦。

     二叉树的另一种常用的存储结构是三叉链。三叉链式在二叉链的基础上再增加一个双亲结点指针域parent。三叉链除基于二叉链的优点外,对于查找当前结点的双亲结点操作实现起来也很容易。相对于二叉链,三叉链的缺点是结构更为复杂,因而每个结点占用的内存单元也更多一些。

  3. 二叉树的仿真指针存储结构

     二叉树的仿真指针存储结构是用数组存储二叉树中的结点,再增加仿真指针域仿真常规指针建立二叉树中结点之间的关系。二叉树的仿真指针存储结构有仿真二叉链存储结构和仿真三叉链存储结构。

     仿真指针存储结构的最大优点是遍历操作实现非常容易。用for循环或while循环就可实现。仿真指针存储结构的最大缺点是可存储的结点个数受初始化定义的数组元素个数限制。

五、树和二叉树的转换

  1. 树转换为二叉树
    • 树中所有相同双亲结点的兄弟结点之间加一条连线
    • 对树中不是双亲结点第一个孩子的结点,只保留它与左兄弟结点之间的连线,删去该结点与双亲结点之间的连线
    • 整理所有保留的和添加的连线,使每个结点的孩子结点连线位于左孩子指针位置,使每个结点的右兄弟结点连线位于右孩子指针位置
  2. 二叉树还原为树
    • 若某结点是其双亲结点的左孩子,则把该结点的右孩子、右孩子的右孩子……都与该结点的双亲结点用线连起来
    • 删除原二叉树中所有双亲结点与右孩子结点的连线
    • 整理所有保留的和添加的连线,使每个结点的孩子结点连线顺序位于下方孩子结点位置

你可能感兴趣的:(二叉树,数据结构,数据结构)