0 阅读5分钟

概念

除第一个元素没有直接前驱,其他每个元素都有一个直接前驱,每个元素都有一个零个或多个直接后继

  • 节点的度、树的度(树内节点的最大值)
  • 叶节点、分支节点、内部节点(除了根和叶子节点)
  • 关系:孩子、双亲、兄弟、子孙、堂兄弟 image.png

image.png

  • 深度、高度
  • 有序树和无序树, 二叉树是有序树

性质

注意:M叉树和度为M的树的区别,M叉树是所有节点的度小于等于m;度为m的树,至少要有一个节点的度为m。

性质主要靠理解

image.png

满二叉树(完美二叉树)、完全二叉树

什么样的二叉树是完全二叉树是一个重要的考点 完全二叉树的特点(以下是重要考点)

  • 叶节点只可能出现在层次最大的两层
  • in/2i\leq\lfloor n/2 \rfloor,则节点i为分支节点,否则为叶节点,最后一个分支节点的编号为 n/2\lfloor n/2 \rfloor
  • 度为1的节点,只可能有一个,该节点只有左孩子,而无右孩子
  • n为奇数,每个分支节点都有左右孩子,n为偶数,编号最大的分支节点(n/2)只有左孩子,没有右孩子 以下特点,还可以用于完全二叉树的数组存储
  • i>1时,节点i的双亲节点的编号为i/2\lfloor i/2 \rfloor
  • 若节点i有左右孩子,则左孩子的编号为2i,右孩子的编号为2i+1

最重要考点的一个性质 推导过程也要详细记忆

两个特殊需要记忆的

  • n0=n2+1
  • 知道节点数求高度(老汤的这个推导写得很垃圾,之后有时间写自己的) image.png

image.png

链式实现

有各种各样的实现方式,区别在于结构体的定义

  • 三叉链表
typedef struct BiTNode {

    TElemType data;          // 数据域


    struct BiTNode *parent;  // 指向双亲的指针域

    struct BiTNode *left;    // 左指针域

    struct BiTNode *right;   // 右指针域

} BiTNode;

  • 二叉链表
typedef struct BiTNode {

    TElemType data;          // 数据域

    struct BiTNode *left;    // 左指针域

    struct BiTNode *right;   // 右指针域

} BiTNode;

顺序结构实现

主要按照完全二叉树的编号来存储,会浪费大量空间

  • 顺序存储空间必须是连续的
  • 要在顺序存储空间上正确表示二叉树结点之间的逻辑关系

这个结点之间关系的计算写出树来现推,不要记忆,下面的图作为一个参考

image.png

遍历二叉树(主要通过链式结构实现)

便利二叉树是按某条搜索路径访问树中每个节点,使得每个节点均被访问一次,而且仅被访问一次,

当拿到一棵树的根节点,就可以顺着左右指针去访问整棵树,所以很多时候给你一棵树,就是给你这棵树的根节点 (这里可以类比线性表的头节点) 所以结构体单独定义一个指针,根节点表示一棵树

先序、中序、后序遍历

先序、中序、后序遍历,这部分掌握得比较牢靠,可以不用管,记住代码是核心

遍历序列确定二叉树

是否由任意两个序列确定一个二叉树?确定的二叉树是否唯一 层序遍历序列和中序遍历序列的结果不是很熟

image.png

注意

递归变非递归

树的先序序列和中序序列的关系:以前序序列作为入栈次序,中序序列作为出栈次序

层次遍历

可以比较方便的找到树的高度

根据遍历结构确定二叉树

线索二叉树(Threaded Binary Tree)

快速找到一个节点的前驱和后继

如何快速找到某个节点的先序遍历的前驱和后继?

运行一遍先序遍历算法,时间复杂度O(n)

如何加快查找一个节点在某一种遍历规律中的前驱和后继的速度?

引入线索二叉树:

  • 快速找到前驱和后继
  • 提高二叉树的存储密度(有些空连域)
  • 加速遍历算法

空连接域存放前驱后继的信息,左指向前驱,右指向后继

注意:对于没有空链接域的节点(既有左右孩子的节点)找前驱和后继还是很不方便

一个重要结论:对于一棵具有n个结点的二叉树,它的空链域的数量是8个

结构体

typedef char TElemType;

Typedef struct BiThrNode{
    TElemType data;
    struct BiThrNode *left;
    struct BiThrNode *right;
    int Ltag;//0表示指向左孩子,1指向前驱
    int Rtag;//0表示指向有孩子,1指向后继
}BiThrNode,*BiThrTree;

代码有些地方想不通,但是不管了,理解过程,以及遍历

  • 最后一个结点的尾指针无论如何都指向头(可能会有一个头节点,如图所示),除了后序线索二叉树
  • 减少了出栈入栈的性能损耗,提升先序遍历的性能,下图所示的结点I为例,要递归回上一颗树才能访问结点E,但是利用空链域保存了结点I的后继结点就不用递归,直接访问,同时E也不需要递归返回直接访问C 虽然时间复杂度仍然是O(N),但是空间复杂度降为O(1)

先序二叉树 image.png

中序二叉树

image.png

后序二叉树

image.png