树--《大话数据结构》

一、树的定义

树是由n(n>=1)个有限结点组成一个具有层次关系的集合,根朝上,叶朝下

树具有以下的特点:
① 每个结点有零个或多个子结点;没有父结点的结点称为根结点;
② 每一个非根结点有且只有一个父结点;
③ 除了根结点外,每个子结点可以分为多个不相交的子树。

注意:
① n > 0时根结点是唯一的,不可能存在多个根节点;
② 由子结点构成的子树个数没有限制,但它们一定是互不相交的。
树--《大话数据结构》_第1张图片

二、树的相关概念

  1. 空树: 树结点的个数(n≥0),当n=0时,称为空树;
  2. 结点间的关系:
    ① 结点的子树的根称为该结点的孩子(Child),相应地,该结点称为孩子的双亲(Parent)
    ② 同一个双亲的孩子之间互称兄弟
    ③ 结点的祖先是从根到该结点所经分支上的所有结点;
    ④ 反之,以某结点为根的子树中的任一结点都称为该结点的子孙
    树--《大话数据结构》_第2张图片
  3. 结点的分类:
    结点的度(Degree): 结点拥有的子树数;
    树的度: 树内各结点的度的最大值;
    叶结点: 度为0的结点,也称为终端结点,无孩子,在树中可以存在多个;
    分支结点: 度不为0的结点,也称为非终端结点
    内部结点: 树中除根结点之外的分支结点,一个双亲多个孩子;
    树--《大话数据结构》_第3张图片
  4. 结点的层次: 由结点位置,从根开始定义,根为第一层,往下递增(同层的结点互为堂兄弟);
    树的深度(Depth): 树中结点的最大层次,也称为高度
    树--《大话数据结构》_第4张图片

三、树的存储结构

  • 双亲表示法:
    每个结点分别由一个数据域和一个指针域构成。数据域存储结点的数据信息,指针域储存双亲的地址。
    注意: 因为根结点没有双亲,故约定其指针域为NULL。

  • 孩子表示法:
    每个结点分别由一个数据域和多个指针域构成。指针域指向每一棵子树的根结点。也称为多重链表表示法
    注意: 因为不同结点的孩子个数可能有差异,故需要设计方案解决:
    ① 按树的度,也就是树中各个结点度的最大值,指定指针域的个数;(浪费内存)
    ② 每个结点指针域的个数等于该结点的度。增添一个专门位置,存储结点指针域的个数;(维护麻烦)
    ③ 将每个结点的孩子排列起来,以单链表作存储结构(叶子结点则此链表为空)。然后将这些链表的头指针,组成一个线性表存储。

  • 孩子兄弟表示法:
    每个结点分别由一个数据域和两个指针域构成。指针域指向该结点的第一个孩子和右兄弟。该方法本质上等价于将任意一个复杂的树,转换成二叉树结构
    注意: 若某结点没有孩子或右兄弟,将对应的指针域设定为NULL。

四、特殊树——二叉树

4.1 二叉树的定义

二叉树是n个结点的有限集合,该集合或者为空集(称为空二叉树),或者由一个根结点和两棵互不相交的(分别称为根结点的左子树、右子树)二叉树组成。

二叉树具有以下特点:
① 每个结点最多只有两棵子树,所以二叉树中的结点度取值只能为三个值——0、1、2
② 左子树和右子树是有顺序的,不能任意颠倒;
③ 即使树中某结点只有一棵子树,也要区分其是左子树还是右子树。

二叉树具有五种基本形态:
① 空二叉树;
② 只有一个根结点;
③ 根结点只有左子树;
④ 根结点只有右子树;
⑤ 根结点既有左子树又有右子树。

4.2 二叉树的存储结构

  • 顺序存储结构: 用一维数组存储二叉树中的结点,并且结点的存储位置(数组的下标),需要体现结点之间的逻辑关系(双亲与孩子、兄弟等)。(维护麻烦、浪费内存,一般不会使用)
    存储时,将目标二叉树看作完全二叉树,对各结点进行层序编号。其编号,就是在数组中存储时的下标。若某个编号对应的结点不存在,在数组中存储特殊标志值表示。
  • 二叉链表: 每个结点分别由一个数据域和两个指针域构成。指针域分别指向存放左、右孩子的地址。如下图:
    二叉链表

4.3 二叉树的性质

  1. 在二叉树的第i层上至多2(i - 1) 个结点(i ≥ 1).;
  2. 深度为k的二叉树至多2k - 1个结点(k ≥ 1) ;
  3. 对任何一棵二叉树,若终端结点数为a,度为2的结点数为b,则a = b + 1
  4. 具有n个结点的完全二叉树的深度为 [log2n] + 1([x]表示不大于x的最大整数);
  5. 如果对一棵有n个结点的完全二叉树(其深度为[log2n] + 1)的结点按层序从上至下、从左至右编号,对任一结点i(1 ≤ i ≤ n)有:
    ① 若i = 1,则结点i是二叉树的根,无双亲;若i > 1,其双亲是结点 [i / 2]
    ② 若2i > n,则结点i无左孩子(结点i为叶子结点);否则,其左孩子是结点2i
    ③ 若2i + 1 > n,则结点i无右孩子;否则,其右孩子是结点2i + 1

4.4 特殊形式二叉树

4.4.1 斜树:

所有结点都只有左子树的二叉树叫左斜树。所有结点都只有右子树的二叉树叫右斜树。这两者统称为斜树。

4.4.2 满二叉树:

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

满二叉树具有以下特点:
① 叶子只能出现在最下一层,出现在其它层就不可能达到平衡;
② 非叶子结点的度一定是2;
③ 在同样深度的二叉树中,满二叉树的结点个数最多,叶子树最多。
树--《大话数据结构》_第5张图片

4.4.3 完全二叉树:

对一个二叉树的结点按层次从上至下、从左至右编号。如果每个编号,与等深度的满二叉树相同位置的结点完全一致。则称该树为完全二叉树。

完全二叉树具有以下特点:
① 叶子结点只能出现在最下两层;
② 最下层的叶子一定集中在左部连续位置;
③ 倒数二层,若有叶子结点,一定都在右部连续位置;
④ 如果结点度为1,则该结点只有左孩子,既不存在只有右子树的情况;
⑤ 同样结点数的二叉树,完全二叉树的深度最小。

4.4.4 线索二叉树:

利用二叉树结点的空指针域,存储该结点以某种次序遍历的前驱、后继(线索),提高遍历效率的同时,增强了内存空间的利用效率。加了线索的二叉链表称为线索链表,相应的二叉树称为线索二叉树。而以某种次序遍历,使一个二叉树变成线索二叉树的过程,称为线索化。
线索二叉树的结点变量,需要包含两个成员标志(ltag、rtag),来表示lchild、rchild是指向左右孩子,还是前驱后继。如下:
在这里插入图片描述

4.5 二叉树的遍历

二叉树的遍历是指从根结点出发,按照某种次序依次访问二叉树中所有结点,使得每个结点被访问一次且仅被访问一次。

  • 前序遍历: 若二叉树为空,则空操作返回;否则先访问根结点,然后前序遍历左子树,再前序遍历右子树(根——左子树——右子树)。如下:
    树--《大话数据结构》_第6张图片
  • 中序遍历: 若二叉树为空,则空操作返回;否则先遍历根结点的左子树,然后访问根结点,再中序遍历右子树(左子树——根——右子树)。如下:
    树--《大话数据结构》_第7张图片
  • 后序遍历: 若二叉树为空,则空操作返回;否则按从左到右、先叶子后结点的方式遍历访问左右子树,最后访问根结点(左子树——右子树——根)。如下:树--《大话数据结构》_第8张图片
  • 层序遍历: 若二叉树为空,则空操作返回;否则从树的第一层,即根结点开始,按从上而下、从左到右的顺序逐个访问结点。如下:
    树--《大话数据结构》_第9张图片

五、树、森林、二叉树的转换

5.1 “树”转换成“二叉树”

① 加线。在所有兄弟结点之间加一条连线;
② 去线。对树中每个结点,只保留它与第一个孩子结点的连线,删除它与其他孩子结点之间的连线;
③ 层次调整。以树的根结点为轴心,讲整棵树顺时针旋转一定角度,使其结构层次分明。注意第一个孩子是二叉树结点的左孩子,兄弟转换过来的孩子是结点的右孩子。
树--《大话数据结构》_第10张图片

5.2 “森林”转换成“二叉树”

① 把每棵树转换为二叉树;
② 第一棵二叉树不动。从第二棵二叉树开始,依次把后一棵二叉树的根结点,作为前一棵二叉树的根结点的右孩子,用线连接起来。当所有的二叉树连接起来后,就得到了由森林转换而来的二叉树。
树--《大话数据结构》_第11张图片

5.3 “二叉树”转换成“树”

① 加线。若某结点A,存在左孩子结点B,则将B的所有右孩子结点,都作为A的孩子,用线连接起来;
② 去线,删除原二叉树中所有结点与其右孩子结点的连线;
③ 层次调整。使之结构层次分明。
如下:
树--《大话数据结构》_第12张图片

5.4 “二叉树”转换成“森林”

① 从根结点开始,若右孩子存在,则把与右孩子结点相连的线删除。再查看分离后的二叉树,若右孩子存在,则连线删除……,直到所有右孩子连线都删除为止;
② 将每棵分离后的二叉树转换成树即可。
树--《大话数据结构》_第13张图片

你可能感兴趣的:(读书笔记)