大话数据结构之树(上)

232 阅读8分钟

一、树的定义

树是n(n>=0)个结点的有限集。
n=0时称为空树。

在任意一颗非空树中:
1、有且仅有一个特定的称为根(root)的结点
2、当n>1时,其余结点可分为m(m>0)个互不相交的有限集T1、T2、......、Tm,其中每一个集合本身又是一棵树,并且称为根的子树(SubTree),如下图所示 在这里插入图片描述


树的定义其实就是我们在讲解栈时提到的递归的方法

对于树的定义还需要强调两点 (1)n>0时,根结点是唯一的,不可能存在多个根结点 (2)m>0时,子树的个数没有限制,但它们一定是互不相交的



1、结点分类

树的结点包含一个数据元素及若干个指向其子树的分支

结点拥有的子树数称为结点的度

叶结点

度为0的结点称为叶结点或终端结点

分支结点

度不为0的结点称为非终端结点或分支结点

在这里插入图片描述 树的度:

树内各结点的度的最大值




2、结点间关系

结点的子树的根称为该结点的孩子(child) 该结点称为孩子的双亲 同一个双亲的孩子之间互称兄弟 结点的祖先是从根到该结点所经分支上的所有结点


3、树的其他相关概念

结点的层次从根开始定义起,根为第一层,根的孩子为第二层


若某结点在第一层,则其子树的根就在第i+1层。 其双亲在同一层的结点互为堂兄弟
树中结点的最大层次称为树的深度或高度,当前树的深度为4 在这里插入图片描述

如果将树种结点的各子树看成从左至右是有次序的,不能更换的,则称该树为有序树,否则称为无序树

森林是m(m>=0)课互不相交的树的集合 对树中每个结点而言,其子树的集合即为森林

在这里插入图片描述

二、树的抽象数据类型

ADT    树(Tree)

Data

    树是由一个根结点和若干棵子树构成。树中结点具有相同的数据类型及层次关系。

Operation

    InitTree(*T): 构造空树T。

    DestroyTree(*T): 销毁树T。

    CreateTree(*T, definition): 按definition中给出树的定义来构造树。

    ClearTree(*T): 若树T存在,则将树T清为空树。

    TreeEmpty(T): 若T为空树,返回true,否则返回falseTreeDepth(T): 返回T的深度。

    Root(T): 返回T的根结点。

    Value(T, cur_e): cur_e是树T中一个结点,返回此结点的值。

    Assign(T, cur_e, value): 给树T的结点cur_e赋值给value。

    Parent(T, cur_e): 若cur_e是树T的非根结点,则返回它的双亲,否则返回空。

    LeftChild(T, cur_e): 若cur_e是树T的非叶结点,则返回它的最左孩子,否则返回空。

    RightSibling(T, cur_e): 若cur_e有右兄弟,则返回它的右兄弟,否则返回空。

    InsertChild(*T, *p, i, c): 其中p指向树T的某个结点,i为所指结点p的度加上1,非空树c与T不相交,操作结果为插入c为树T中p所指结点的第i棵子树。

    DeleteChild(*T, *p, i): 其中p指向树T的某个结点,i为所指结点p的度,操作结果为删除T中p所指结点的第i棵子树。

endADT




三、树的存储结构

1、双亲表示法

除了根结点外,其余每个结点不一定有孩子,但一定有且仅有一个双亲 用一组连续空间存储树的结点,同时在每个结点中,附设一个指示器指示其双亲结点在数组中的位置


结点结构如下:

(其中data是数据域,存储结点的数据信息;parent是指针域,存储该结点的双亲在数组中的下标)

(由于根结点没有双亲,我们可以将根结点的位置域设置为-1) 在这里插入图片描述

//树的双亲表示法结点结构定义
#define MAX_TREE_SIZE 100
typedef int TElemType;//树结点的数据类型,目前暂定为整型
typedef struct PTNode{//结点结构
    TElemType data;//结点数据
    int parent;//双亲位置
}PTNode;
typedef struct{//树结构
    PTNode nodes[MAX_TREE_SIZE];//结点数组
    int r, n;//跟的位置和结点数
}PTree;

在这里插入图片描述

这样的存储结构,我们可以根据结点的parent指针很容易找到它的双亲结点,所用的时间复杂度为0(1),直到parent为-1时,表示找到了树结点的根。



改进

如果需要访问结点的孩子,则需要遍历整个结构,不如增加一个最左边孩子的域,即长子域 (如果结点没有孩子,则将其长子域设置为-1)

在这里插入图片描述

四、二叉树的定义

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

4.1、二叉树的特点

  1. 每个结点最多有两棵子树,所以二叉树不存在度大于2的结点
  2. 左子树和右子树是有顺序的,次序不能任意颠倒
  3. 即使树中某结点只有一棵子树,也要区分它是左子树还是右子树

如果一棵二叉树由三个结点组成的话,那么这棵二叉树有几种形态呢?

在这里插入图片描述

4.2、特殊二叉树

1、斜树

在这里插入图片描述

所有结点都只有左子树的二叉树叫左斜树;所有结点都只有右子树的二叉树叫右斜树
左斜树跟右斜树统称为斜树。
它的特点就是每一层只有一个结点,结点的个数与二叉树的深度相同,类似线性表(线性表可以理解为树的一种极其特殊的表现形式)



2、满二叉树

在这里插入图片描述

如果二叉树每个分支结点都存在左右子树(叶子除外),叶子都在同一层,这种二叉树称为满二叉树。

满二叉树的特点

  1. 叶子只能出现在最下一层,出现在其他层就不可能达成平衡
  2. 非叶子结点的度一定是2
  3. 在同样深度的二叉树中,满二叉树的结点个数最多,叶子树最多

3、完成二叉树

对一棵具有n个结点的二叉树按层序编号,如果编号为i(1 ≤ i ≤ n)的结点与同样深度的满二叉树中编号为i的结点在二叉树中位置完全相同,则这棵二叉树称为完全二叉树

完全二叉树呢,其实是建立在满二叉树的基础上的,具体而言就是在满二叉树右下角的地方开始往左边依次砍n个结点后形成的即为完全二叉树!


在满二叉树右下角往左边依次砍掉1个结点后,就变成了完全二叉树

在这里插入图片描述

在满二叉树右下角往左边依次砍掉2个结点后,就变成了完全二叉树

在这里插入图片描述

当砍掉0个结点后,也是一棵完全二叉树,只是这时也是一棵满二叉树

在这里插入图片描述

记住几个关键点:满二叉树、右下角开始、依次往左


完全二叉树的特点

  1. 叶子结点只能出现在最下两层
  2. 最下层的叶子一定集中在左部连续位置
  3. 倒数二层,若有叶子结点,一定都在右部连续位置
  4. 如果结点度为1,则该结点只有左孩子,即不存在只有右树的情况
  5. 同样结点数的二叉树,完全二叉树的深度最小

4.3、二叉树的性质

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

在这里插入图片描述

如果i = 1,则结点i是二叉树的根,无双亲;如果i > 1,则其双亲是结点⌊i / 2⌋

对于性质5的第一条来说,这是很显然的,因为i = 1时就是根结点。 i > 1时,比如结点5,那么它的双亲就是⌊i / 2⌋,也就是⌊5 / 2⌋ = 2, 结点9,它的双亲就是⌊i / 2⌋,也就是⌊9 / 2⌋ = 4


如果2i > n,则结点i无左孩子(结点i为叶子结点);否则其左孩子是结点2i

对于性质5的第二条来说,比如结点7,因为2 × 7 = 14超过结点总数10,所以结点7没有左孩子 同理,对于结点5,因为2 × 5 = 10等于结点总数10,所以它的左孩子是结点2i,也就是2 × 5 = 10结点


如果2i + 1 > n,则结点i无右孩子;否则其右孩子是结点2i + 1

对于性质5的第三条,比如结点5,因为2 × 5 + 1 = 11,大于结点总数10,所以它没有右孩子 同理,结点3,因为2 × 3 + 1 = 7,小于结点总数10,所以它的右孩子是结点7