一些概念
- 树:N个结点的有限集
- 结点:一个数据元素及指向子树的分支
- 结点的度:结点的子树数
- 叶子结点:度为0的结点
- 分支结点:度不为0的结点
- 树的度:树中结点的度的最大值
- 树的深度:树的最大层数
- 二叉树:每个结点至多有2个子树,且有左右之分
- 二叉树5个基本形态:空/根结点/只有左子树/只有右子树/左右子树都存在
一些性质
- 二叉树的第(i)层最多有(2^{i-1})个结点
- 深度为(k (k\geq1))的二叉树最多有(2^k-1)个结点
- 对于任何一个二叉树,如果其叶子结点数为(n_0),度为2的结点数为(n_2),则(n_0=n_2+1)
满二叉树和完全二叉树
- 满二叉树:深度为(k)且总共有(2^k-1)个结点的二叉树
- 完全二叉树:深度为(k)且总共有(n)个结点的二叉树,当且仅当其每个结点都与深度为(k)的满二叉树从1到(n)的结点一一对应
完全二叉树性质
- (n)个结点的完全二叉树的深度为(\log_{2}n+1)
- 对于(n)个结点的完全二叉树的任一结点(i)
- 若(i=1)则为根结点,若(i>1), (i)的父结点为(i/2)
- 若(2i>n),则(i)无左子树,否则左孩子结点为(2i)
- 若(2i+1>n),则(i)无右子树,否则右孩子结点为(2i+1)
二叉树的存储结构
任何数据结构都可以用顺序存储和链式存储
二叉链表
最常用的存储方式
$n$个结点的二叉链表中,有$n+1$个空链域
简单顺序存储
将二叉树转为完全二叉树
虚拟出空结点
将完全二叉树上编号(i)的结点存储在数组的(i-1)位置
空结点对应的数组元素存null
如果是单边树,会很浪费空间,一般不使用这种方法
双亲表示法
每个结点都记住父结点在数组中的下标
- 优点:容易找到父结点
- 缺点:找子结点需要遍历整个结构
孩子表示法
是数组和链表结合的存储方法
每个结点需要存储它的子结点在数组中的下标链表
带父结点的孩子链表
将双亲表示法和孩子表示法结合起来
兄弟孩子表示法
另一种链式存储方法
结点的左孩子为从左往右的第一个子结点,右孩子为其兄弟结点
常用于树转换为二叉树,森林转换为二叉树
任何一个与树对应的二叉树,右子树都为空
先将每个树转为二叉树,再将每个二叉树根节点连接
二叉树的遍历
以二叉链表结构为例
先序遍历
中序遍历
后序遍历
层序遍历
深度优先遍历dfs即为先序遍历,广度优先遍历bfs即为层序遍历
如果增加一些辅助数据域,比如父结点或访问位,也可以不借助其他数据结构进行遍历
给定一个数组,按层序构建一个完全二叉树
使用完全二叉树的性质,编号为$i$的结点,左孩子结点的编号为$2i$,右孩子结点的编号为$2i+1$
数组下标从0开始,树的序号从1开始,所以再加1
Huffman树(最优二叉树)
一些概念
- 路径:从一个结点到另一个结点之间的分支
- 路径长度:路径上的分支数
- 树的路径:从根结点到每一个结点的路径长度之和
- 带权路径长度:路径上分支数量与权值的乘积
Huffman树的带权路径长度最短
Huffman树没有度为1的结点,是严格的二叉树
一些练习
度为2的树与二叉树的区别
- 二叉树的度最大值为2,二叉树的子节点有左右顺序,而度为2的树子节点不一定有序
$n$个结点的二叉链表中有多少空链域
- $n$个结点的二叉链表中有$2n$个链域,除了根结点每个结点都占用一个链域,即$n-1$个链域,则空链域为$2n-(n-1)=n+1$个
一个含有$n$个结点的$k$叉树,可能的最大深度和最小深度是多少
- 最大为深度为$n$(单边树),最小深度为$log_{k}n+1$(完全$k$叉树)
对于非叶子结点都有左右子树的二叉树,有$n$个叶子结点的树中总共多少个结点
- 对于任何二叉树,度为$0$的结点$n_0$和度为$2$的结点$n_2$有$n_0=n_2+1$,所以该树共有$n+n-1=2n-1$个结点
找出满足下列条件的二叉树
- 先序和中序遍历,得到的结果相同
- 后序和中序遍历,得到的结果相同
- 先序和后续遍历,得到的结果相同