数据结构——第六章(树)

1. 树

1.1 树的基本概念

  • 树:由N个节点(N>=0)构成的集合,有且仅有一个根节点,且树是递归定义的结构。
  • 当n>1时,有m个互不相交的有限集合(判断是否为树:观察他们的子树是否相交)
  • 结点的度:节点拥有子树的数量/分支的数量(度为0——叶子/终端节点)
  • 树的度:树中所有节点的度数最大值。
  • 深度:根节点开始自顶向下累加。
  • 树的深度:树中节点的最大层数。
  • 路径长度:路经过边的个数

1.1 树的性质

  • 树中的节点数等于所有节点的度数加1(分支数量+根节点)
  • 度为m的树中第h层上至多有 m h - 1 个节点(数学归纳法)
  • 树的节点总个数确定下,“完全”m插树,高度最小
  • 树的节点总个数确定下,全部只有一个孩子节点的时候,高度最大
  • 高度为h的m叉树至多有 1 × 1 - m h 1 - m 个节点(满二叉树时,等比求和)

最重要的公式( N i ——度为i的节点个数)
N总= N o + N 1 + N 2 … … + N m (N总——树的总节点个数)
B= 0 × N 0 + 1 × N 1 + … . + m × N m (树的分支数,即边数)
N总= B+1

1.2 树的存储结构

  • 孩子表示法:用指针表示每个节点的孩子节点
  • 双亲表示法:用指针表示每个节点的双亲节点
  • 双亲孩子表示法:用指针表示每个节点的双亲节点和孩子节点
  • 孩子兄弟表示法:用指针表示每个节点的孩子节点和兄弟节点

2. 二叉树

2.1 二叉树概念

  • 一个二叉树是节点的一个有限集合,该集合或为空,或由根节点加上两颗分别称为左子树和右子树的二叉树组成

2.2 二叉树的特点

  • 左右子树有顺序
  • 每个节点最多有两颗子树

2.3 二叉树的5种形态

2.4 特殊二叉树

  • 斜树:左斜树,右斜树
  • 满二叉树:只有度为2和度为0的节点(计算时利用二叉树的性质)
  • 完全二叉树:和同样深度的满二叉树中的节点位置相同
    数据结构——第六章(树)_第1张图片

2.5 二叉树的性质(对比树度为2的情况,考试很重要)

  • 树不为空时,第h层上至多有 2 h - 1 个节点(单层节点)
  • 深度为h的二叉树至多有 2 h - 1 个节点(总节点)
  • 叶子节点数=度为2的节点数+1( N 0 = N 2 + 1 利用上面的三条公式推导)
  • 含义N个节点的完全二叉树深度为 h = ⌈ log 2 N + 1 ⌉
  • 具有N个节点的完全二叉树按层序编号i(1<=i<=N):i>1 节点双亲节点编号为 ⌊ n 2 ⌋
  • 2i<=N节点i的左孩子为2i或无左孩子、2i+1<=N节点i的右孩子为2i+1或无右孩子
  • 性质5例子:
    数据结构——第六章(树)_第2张图片

2.6 完全二叉树的性质(满二叉树是特殊的完全二叉树)

  • 叶字节点只可能在最大两层上
  • i <= n/2 是分支节点(i为下标,n为节点)
  • i > n/2 是叶子节点(用于求完全二叉树的第一个叶子节点
  • 完全二叉树只可能有一个或没有度为1的节点,且该节点只有左孩子
  • 按层序编号后,一旦出现某i节点为叶字节点,则大于该节点的均为叶字节点

对于完全二叉树,n为偶数:叶子节点的个数为n/2,n为奇数:叶子节点的个数为(n+1)/ 2

2.7 二叉树的存储结构

  • 顺序存储:数组,适合存放完全二叉树和满二叉树(不会浪费空间)
  • 链式存储:数据域,左孩子,右孩子
typedef struct BiTNode {
    ElemType data;
    struct BiTNode *lchild, *rchild;
}BiTNode, *BiTree;

重要结论:含有n个节点对的二叉链表含有n+1个空链域(利用空链域来组成线索链表)

2.8 二叉树的遍历(根的位置)

  • 前序遍历:NLR
    数据结构——第六章(树)_第3张图片
  • 中序遍历:LNR
    数据结构——第六章(树)_第4张图片
  • 后序遍历:LRN
  • 递归写法(打印操作在I II III位置为不同的遍历)
void Order(BiTree T) {
    if(T != NULL) {
        // Ⅰ 先序遍历
        Order(T->lchild);
        // Ⅱ 中序遍历
        Order(T->rchild);
        // Ⅲ 后序遍历
    }
}

2.9 线索二叉树(利用n个节点有n+1空指针)

  • 二叉树结构多了两个标志位
typedef struct BiThrNode {
	char data;
	struct BiThrNode *lchild,*rchild;		
	PointerTag ltag;
	PointerTag rtag;
} BiThrNode,*BiThrTree;	
  • 结点结构 : ltag lchild data rchild rtag
  • ltag = 0 (左孩子) ltag = 1 (前驱结点)
  • rtag = 0 (右孩子) rtag = 1 (后继结点)
  • 对二叉树以某种次序遍历使其变成为线索二叉树的过程叫线索化
  • 仿照线性表,线索链表上也加一个头结点(双向链表连接头尾)
  • 目的:加快查找节点的前驱和后继的速度

2.10 二叉排序树(二叉查找树、二叉搜索树)

  • 根节点的值大于其左子树中任意一个节点的值,小于其右节点中任意一节点的值,这一规则适用于二叉查找树中的每一个节点。
  • BST(Binary Search Tree)的中序遍历就是升序
  • 高度平衡二叉树:一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过1。

数据结构——第六章(树)_第5张图片

3. 树与二叉树与森林

3.1 如何将一颗树转化为二叉树(二叉树转换成树反向操作即可)

  • 将所有的兄弟节点连接起来
  • 将每个节点的子树分支,从左往右,除第一个以外全部删除
  • 以根节点为轴心,顺时针旋转45°得到二叉树

3.2 如何将森林转化为二叉树(二叉树转换成森林反向操作即可)

  • 将每颗树转化成相应的二叉树
  • 将步骤1中得到的各个二叉树的根节点看做是兄弟连接起来

3.3 树与二叉树的遍历

  • 树的先序遍历=它的二叉树的先序遍历
  • 树的后序遍历=它的二叉树的中序遍历

4.huffmanTree

4.1 huffmanTree基本概念

  • 路径:从一个结点到另一个结点经过的所有节点
  • 路径长度:从一个结点到另一个结点经过的所有的边的数量
  • 结点的带权路径长度:树的根结点到该节点的路径长度和该点权重的乘积

如图1-1:H权重为3,从根节点到该节点的路径长度也为3,因此H结点的带权路径长度为 3*3=9

  • 树的带权路径长度(WPL):一颗树中所有叶子结点的带权路径长度之和,被称为树的带权路径长度

如图1-1:树的带权路径长度为 3 × 3 + 6 × 3 + 1 × 2 + 4 × 2 + 8 × 2 =53

  • huffman树:叶子节点和权重确定的情况下,带权路径长度最小的二叉树,也称为最优二叉树

4.2 给定权重如何构造huffman树

  • 将N个结点分别作为N颗含有一个结点的二叉树,构成森林F
  • 构造一个新节点,并从F中选取两颗权值最小的书作为新结点的左右子树,并且将新及诶点的权值置为左右子树的权值之和
  • 从F中删除刚才选出的两棵树,同时将新得到的树加入到F中
  • 重复步骤2,3,直至F中只剩下一棵树为止

给定权重1,3,4,6,8构造huffmanTree,左侧权值最小为huffmanTree
原则上:权重小的节点远离树根,权重大的靠近树根

5.huffmanCode

5.1 huffmanCode基本概念

  • 用于信息压缩采用不定长编码格式(比定长编码更节省空间)
  • 根据给定信息中各个字符出现的频次,动态生成最优的编码

5.2 huffmanCode的生成过程

假如一段信息里只有A,B,C,D,E,F这6个字符,他们出现的次数依次是2次,3次,7次,9次,18次,25次,如何设计对应的编码呢?

  • 1.根据权重生成huffmanTree,节点左分支为0,右分支为1
  • 2.huffmanTree到每一个节点的路径,都可以等价为一段二进制编码(huffmanTreeCode)
  • 3.叶子结点的权重对应字符出现的频次,结点的路径长度对应字符的编码长度

树笔记终于写完了,我都快变树了
学习资源(感谢各位大佬):
Bilibili:小甲鱼_数据结构C语言版(学校老师讲课太无聊了)
借鉴了一下三位大佬的笔记和图 Java修炼之路、 VictorWu、梦想橡皮擦

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