作者:fover黄瓜小妞1 | 来源:互联网 | 2023-09-06 09:37
六、 树
树是n个结点的有限集,n=0时称为空树。
任意一棵非空树中:
- 有且仅有一个特定的称为根的结点
- 当n>1时,其余结点可分为m个互不相交的有限集T1、T2...Tm,每一个集合本身又是一棵树,称为子树
结点分类
度:结点拥有的子树数称为结点的度
- 根结点
- 叶结点
树的表示方法
双亲表示法:一组连续空间存储树的结点,同时在每个结点中,附设一个指示器指示其双亲结点到链表的位置
![](https://img.php1.cn/3cd4a/189d8/978/7dbdf0f38ad53545.jpeg)
data是数据域,parent是指针域
![](https://img.php1.cn/3cd4a/1eebe/cd5/7d7ef3f69d479716.webp)
上述结构如果要知道结点的孩子是什么,就需要遍历整个结构才行
增加一个结点最左边的域(相当于长子),如果没有孩子的结点,这个长子域就设置为-1
![](https://img.php1.cn/3cd4a/1eebe/cd5/443b30bb45e66690.webp?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzI4NDAwNjI5,size_16,color_FFFFFF,t_70)
但是长子表示了出来,还有次子,次次子。。。及兄弟关系为表示出来
那就增加一个右兄弟域来体现兄弟关系,也就是说,每一个结点如果存在右兄弟,则记录下右兄弟的下标,不存在设为-1
![](https://img.php1.cn/3cd4a/1eebe/cd5/a1be7872e8d4934f.webp?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzI4NDAwNjI5,size_16,color_FFFFFF,t_70)
孩子表示法:每个结点有多个指针域,其中每个指针指向一棵子树的根结点--多重链表表示法
方案一:树的度是树各个结点度的最大值 浪费大量的空间
![](https://img.php1.cn/3cd4a/1eebe/cd5/8373b1277127c518.webp)
![](https://img.php1.cn/3cd4a/1eebe/cd5/d67981797265d9c7.webp?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzI4NDAwNjI5,size_16,color_FFFFFF,t_70)
方案二:取一个位置来存放结点的度,节省空间 每个结点的链表是不同的结构,浪费时间
![](https://img.php1.cn/3cd4a/1eebe/cd5/7cccb7e4b6cb5cb8.webp?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzI4NDAwNjI5,size_16,color_FFFFFF,t_70)
最终的孩子表示法:把每个孩子结点排列起来,以单链表作存储结构,则n个结点有n个孩子链表,如果是叶子结点则此单链表为空
![](https://img.php1.cn/3cd4a/1eebe/cd5/b428d8f746fb8d47.webp?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzI4NDAwNjI5,size_16,color_FFFFFF,t_70)
孩子兄弟表示法:任意一棵树,它的结点的第一个孩子如果存在就是唯一的,它的右兄弟存在也是唯一的。设置两个指针,分别指向该结点的第一个孩子和此结点的右兄弟
![](https://img.php1.cn/3cd4a/1eebe/cd5/72fd2c126203a875.webp)
![](https://img.php1.cn/3cd4a/1eebe/cd5/bff2716168d1ed7b.webp?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzI4NDAwNjI5,size_16,color_FFFFFF,t_70)
二叉树
定义:是n个结点的有限集合,该集合或者为空集,或者由一个结点和两棵互相不相交的、分别称为根结点的左子树和右子树的二叉树组成。
特殊的二叉树:
- 斜树:所有的结点都只有左子树的二叉树叫做左斜树,所有结点都是只有右子树的二叉树叫右斜树
- 满二叉树:在一棵二叉树中,如果所有分支结点都存在左子树和右子树,并且所有叶子都在同一层上
- 完全二叉树:
所有的叶结点都出现在第k层或k-l层(层次最大的两层)对任一结点,
如果其右子树的最大层次为L,则其左子树的最大层次为L或L+l。
二叉树的性质:
- 在二叉树的第i层上至多有
![](https://img.php1.cn/3cd4a/1eebe/cd5/443b30bb45e66690.webp?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzI4NDAwNjI5,size_16,color_FFFFFF,t_70)
二叉树的存储结构
顺序存储结构
二叉链表
二叉树每个结点最多有两个孩子,左指针和右指针
![](https://img.php1.cn/3cd4a/1eebe/cd5/8be1ccb5166feb93.webp)
二叉树的遍历
以子结点为转折点,先遍历子结点,则为前序遍历
- 前序遍历
- 中序遍历
- 后续遍历
- 层序遍历:一层一层的遍历
二叉树的建立
![](https://img.php1.cn/3cd4a/1eebe/cd5/8373b1277127c518.webp)
为了让每个结点确认是否右左右孩子,对这棵树进行扩展,引入虚结点,值为"#"
线索二叉树
![](https://img.php1.cn/3cd4a/1eebe/cd5/ff61bfdd3c0af92e.webp?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzI4NDAwNjI5,size_16,color_FFFFFF,t_70)
上图中存在很多空指针域
一个有n个结点的二叉链表,每个结点有指向左右孩子的两个指针域,一共有2n个指针域,有n-1条分支线,存在2n-(n-1)=n+1个空指针域。
如果事先知道每个结点的前驱结点和后继结点
指向前驱和后继的指针称为线索,加上线索的二叉链表称为线索二叉链表
![](https://img.php1.cn/3cd4a/1eebe/cd5/8343fdbffb0056b5.webp?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzI4NDAwNjI5,size_16,color_FFFFFF,t_70)
树、森林与二叉树的转换
树-->二叉树
![](https://img.php1.cn/3cd4a/1eebe/cd5/6789f68dabde0aed.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzI4NDAwNjI5,size_16,color_FFFFFF,t_70)
![](https://img.php1.cn/3cd4a/1eebe/cd5/21e585a7e21fc7dc.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzI4NDAwNjI5,size_16,color_FFFFFF,t_70)
森林-->二叉树
![](https://img.php1.cn/3cd4a/1eebe/cd5/67cc2e96eddffff8.png)
![](https://img.php1.cn/3cd4a/1eebe/cd5/d67981797265d9c7.webp?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzI4NDAwNjI5,size_16,color_FFFFFF,t_70)
二叉树-->树
![](https://img.php1.cn/3cd4a/1eebe/cd5/70be2ca197098d98.webp)
![](https://img.php1.cn/3cd4a/1eebe/cd5/d67981797265d9c7.webp)
![](https://img.php1.cn/3cd4a/1e618/cd5/af17da15769ccb2e.jpeg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzI4NDAwNjI5,size_16,color_FFFFFF,t_70)
二叉树-->森林
![](https://img.php1.cn/3cd4a/1eebe/cd5/433ea70d6ea577b1.jpeg)
![](https://img.php1.cn/3cd4a/1eebe/cd5/d05d9dfd09a56332.webp?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzI4NDAwNjI5,size_16,color_FFFFFF,t_70)
树与森林的遍历
树
- 先根遍历树
- 后跟遍历树
森林
- 前序遍历
- 后序遍历
赫夫曼树及其应用
赫夫曼树:权重最大的作为根结点
![](https://img.php1.cn/3cd4a/1eebe/cd5/7d7ef3f69d479716.webp?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzI4NDAwNjI5,size_16,color_FFFFFF,t_70)
路径:从树中一个结点到另一个结点之间的分支构成两个结点的路径,路径上的分支数目称为路径长度
树的路径长度:从根结点到每个结点之间的距离
二叉树a:![](https://img.php1.cn/3cd4a/1eebe/cd5/5b97d3b808d031e2.webp)
二叉树b:![](https://img.php1.cn/3cd4a/1eebe/cd5/d84f9786330d9e41.png)
考虑权值--带权路径长度WPL最小的二叉树称做赫夫曼树
![](https://img.php1.cn/3cd4a/1eebe/cd5/6c257b6ba227cc3e.webp)
![](https://img.php1.cn/3cd4a/1eebe/cd5/d34245582687a4e6.webp)
赫夫曼树的构建
![](https://img.php1.cn/3cd4a/1e618/bdf/129913486c37ddf6.jpeg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzI4NDAwNjI5,size_16,color_FFFFFF,t_70)
![](https://img.php1.cn/3cd4a/1eebe/cd5/780a3060eeed6a4e.webp)
![](https://img.php1.cn/3cd4a/1eebe/cd5/ed19db63ee478b98.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzI4NDAwNjI5,size_16,color_FFFFFF,t_70)
![](https://img.php1.cn/3cd4a/1eebe/cd5/ddcc574beb16294e.jpeg)
![](https://img.php1.cn/3cd4a/1eebe/cd5/780a3060eeed6a4e.webp?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzI4NDAwNjI5,size_16,color_FFFFFF,t_70)
赫夫曼树编码
有段文字"BADCADFEED"传输,但是用二进制时所需字节编码太过长
![](https://img.php1.cn/3cd4a/1e618/bdf/129913486c37ddf6.jpeg)
![](https://img.php1.cn/3cd4a/1eebe/cd5/43a754c811e7ec5c.webp)
当按照字符出现的频率,可以构造赫夫曼树
![](https://img.php1.cn/3cd4a/1eebe/cd5/2fdc212433a29829.png)
构造赫夫曼树后:
![](https://img.php1.cn/3cd4a/1eebe/cd5/011ac27956d007f0.webp?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzI4NDAwNjI5,size_16,color_FFFFFF,t_70)
但是出现WPL变得很大,编码效率不高,
因此还是用0和1编码更为效率
![](https://img.php1.cn/3cd4a/189d8/978/7dbdf0f38ad53545.jpeg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzI4NDAwNjI5,size_16,color_FFFFFF,t_70)
![](https://img.php1.cn/3cd4a/1eebe/cd5/0ef126b5295c089b.webp)
![](https://img.php1.cn/3cd4a/1eebe/cd5/5287a7b3296ea13e.webp)