带权二叉树

引入路径相关知识

  • 结点之间的路径长度:到达两结点之间的路径分支数就是路径长度。

  • 树的路径长度:根结点到每一个结点之间的路径长度之和。

      解释:因为说的是树,包含整一棵树的,
    从根结点到每一孩子结点的路径长度加起来的总和成为 “树” 的路径长度。
    对后面解释哈夫曼树非常有用。

权值的解释

  • 例子:好比从广州到成都,两个结点之间所需要的车费就是权值
  • 通常给出的是去往下一结点的权值,也就是结点的权值
  • A->B,一般会给出B对应的权值,B的权值就是A到B的路径权值
    @@我们接下去要特别研究的哈夫曼树其实就是带权的二叉树@@

认识WPL

WPL(带权路径长度)= 节点全值 * 路径长度之和

  • 说简单点就是二叉树的带权路径长度之和就是WPL。
    (根结点到每一个结点的带权路径之和就是WPL)

最优二叉树

我在构造哈夫曼树的时候意识到如果不按照规定的方法构造二叉树的话就会造成很多种可能,构造出的二叉树也不尽相同,所以我们的前辈哈夫曼博士就想了一个办法就是构造最优二叉树,最优二叉树就是我们要学习的哈夫曼树吗。

  • 最优二叉树就是在众多解法中找到WPL最小那一棵二叉树,这一棵就叫做哈夫曼树。

构造哈夫曼树的过程

我对哈夫曼树如何建立的操作的理解

  • 对于给出n个带权结点,这里指的是结点,这些结点暂时还没有连通,每一个结点独立开,把这些结点称为根结点,他们是一个集合。
  • 其次我们在这些根结点权值中找到最小的两个结点,然后用一个全新的根结点将其做成二叉树。注意,我们默认把最小的放在左边,次小的(比左边大的)放在右边。
  • 该新二叉树的左右两个权值加起来就变成了新的二叉树的根结点权值,把该新根结点放进剩下的结点中作为一个集合。
  • 继续回到集合中,找两个最小的权值进行重复操作。
    如此一来当根结点只剩下一个的时候就是生成了一个哈夫曼树了。

可以看下图作为一个例子:

总结:哈夫曼树生成过程产生的结点规律:n -> n-1
其实能隐隐约约感受到新生成结点的数量规律,每找到两个权值最小的结点就会生成一个新根结点加进集合中,假设原先有n个根结点在集合中,那规律就是生成一次新根,就会减少一个根结点,那么最后就会生成n-1个新的,注意是新的结点,不是n-1个根结点,我们最后是只剩下一个二叉树根结点。

  • 最后二叉树中所有的结点数:n + n - 1 = 2n - 1 ,就是最终的总结点数。

哈夫曼树的应用

最优二叉树优点

  • 最优二叉树有一个厉害的点是能够保证每一个叶子结点所经过的路径是不相同的。
  • 我们通过这个路径不同的对其进行应用,就可以对应到编码和解码。因为我们能保证每一个在叶子结点的信息都有唯一对应的编码形式。
  • 编码容易解码难,因为我们有时候拿的不是自己编的码,需要结别人的编码时候就会显得异常困难。

其实哈夫曼树的精髓就在于构造,不断生成新结点把两小权值连在一起。 这里需要和二叉搜索树进行区分开,因为哈夫曼树针对于叶子结点的,二叉搜索树是每一个结点都有他对应的信息,会用于增删查改。
这里我们就先对哈夫曼树进行深入了解,会了哈夫曼树,二叉搜索树学起来就很简单。

建立哈夫曼树

明确三个任务

  • ①先对给出的n根结点的信息复制到一个2n-1的二维数组当中
  • ②在2n数组中且在没有父母结点元素中找到最小的那两个元素进行合并,这里的合并并不指真正把他合并,只是把父母结点修改成同一个父母结点就行。
  • ③然后就是把两个结点的权值加起来,作为新结点也就是这两个结点的父结点的权值,再把找到的这两个的父母结点修改成同一个。
  • 注意,我们找到的父母结点插入位置是在 n + 1 的这个位置开始,然后每找到一个就往下加入,直到插完插到2n-1位置就代表该哈夫曼树建立成功。
  • ④在我们寻找最小值的时候那个for循环切记不能越界或者不是当前结点数量。
  • ⑤结点数量在变化,我们每次寻找最小结点的时候那个条件判断也要跟着变化,所以这时候结构体中要时刻记录着结点数量,我们可以用结点数量作为循环条件。
    注意的细节:
  • 建立二叉树的时候一定要注意对数组下标不要越界。
  • 叶子结点是最终二叉树所有的结点的两倍减一倍数。
  • 其次在寻找两个最小结点的时候要找没有父母结点的,也就是还没有组成一对的根结点。
  • 组成的新的根结点是加入到n+1的数组下标中,凡是新结点都要接入到数组中。
  • 因此寻找最小两个结点的时候也要在新加入的父母结点中找,简单来说就是找最小值的时候一直找没有父母结点的就行,直到剩下最后一个作文二叉树根结点就不需要找了,根结点也没有父母结点。

代码如下:

PS:因为鄙人为了方便自己记录,直接浪费两个数组中第一个元素,都将其设置为空或者不管。因此我们计算的时候就不用绞尽脑汁的去想还要加一的事情了。所以我一般是直接新建2n个空间的数组,然后慢慢存。

结构体代码部分

typedef struct _hafuman{
int wight;
int parent;
int lchild;
int rchild;
}HF; typedef struct _HF_Tree{
HF hafuman[17];
int hflength;
int leaves;
}HF_Tree; HF_Tree Tree;

建立操作代码

这里的Find_Minindex(Tree)函数是寻找Tree中最小的一个元素,且返回该元素的下标,找到后要立马把该最小结点的父母结点进行修改,修改后才能继续用,想要找两个就用两次就好了。

void Make_hafuman(HF_Tree* Tree)
{
int i = Tree->leaves+1;
int j, index = 0, lch, rch;
while( i < Tree->leaves*2)
{
lch = Find_Minindex(Tree);
Tree->hafuman[lch].parent = i;
Tree->hafuman[i].lchild = lch; rch = Find_Minindex(Tree);
Tree->hafuman[rch].parent = i;
Tree->hafuman[i].rchild = rch; Tree->hafuman[i].wight = (Tree->hafuman[lch].wight + Tree->hafuman[rch].wight);
i++;
Tree->hflength++;
}
}

找到最小结点(※难点)

int Find_Minindex(HF_Tree* Tree)
{
int length = sizeof(Tree->hafuman)/sizeof(HF);
//printf("暂停测试:%d",length);
int i, min = 1000000, index = 0; for(i = 1; i <= Tree->hflength; i++)
{
if(Tree->hafuman[i].parent == 0)
{
if(Tree->hafuman[i].wight < min)
{
min = Tree->hafuman[i].wight;
index = i;
}
}
}
return index;
}

附上建立哈夫曼树源代码

#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h> typedef struct _hafuman{
int wight;
int parent;
int lchild;
int rchild;
}HF; typedef struct _HF_Tree{
HF hafuman[17];
int hflength;
int leaves;
}HF_Tree; HF_Tree Tree; void Make_hafuman(HF_Tree*); int Find_Minindex(HF_Tree*); //生成哈夫曼树
int main()
{
/*
给出 n 个元素数组作为根节点权值
生成一个2n 空间数组,先把这个权值赋值进去
结构体数组:权值域,父母域,左孩子,右孩子(左小右大) 生成哈夫曼树函数参数:数组地址,
*/ int w[9] = {0, 7, 19, 2, 6, 32, 3, 21, 10};
int i,sum =0;
for(i = 1; i < sizeof(w)/sizeof(int); i++)
{
Tree.hafuman[i].wight = w[i];
Tree.hafuman[i].lchild = 0;
Tree.hafuman[i].parent = 0;
Tree.hafuman[i].rchild = 0;
Tree.leaves++;
sum+=Tree.hafuman[i].wight;
}
Tree.hflength = Tree.leaves;
printf("%d,总和:%d\n",Tree.leaves, sum);
Make_hafuman(&Tree); for(i = 1; i <= Tree.hflength; i++)
{
printf("%d:%d,%d,%d,%d\n",i, Tree.hafuman[i].wight, Tree.hafuman[i].parent, Tree.hafuman[i].lchild,Tree.hafuman[i].rchild);
} return 0;
} void Make_hafuman(HF_Tree* Tree)
{
int i = Tree->leaves+1;
int j, index = 0, lch, rch;
while( i < Tree->leaves*2)
{
lch = Find_Minindex(Tree);
Tree->hafuman[lch].parent = i;
Tree->hafuman[i].lchild = lch; rch = Find_Minindex(Tree);
Tree->hafuman[rch].parent = i;
Tree->hafuman[i].rchild = rch; Tree->hafuman[i].wight = (Tree->hafuman[lch].wight + Tree->hafuman[rch].wight);
i++;
Tree->hflength++;
}
} int Find_Minindex(HF_Tree* Tree)
{
int length = sizeof(Tree->hafuman)/sizeof(HF);
//printf("暂停测试:%d",length);
int i, min = 1000000, index = 0; for(i = 1; i <= Tree->hflength; i++)
{
if(Tree->hafuman[i].parent == 0)
{
if(Tree->hafuman[i].wight < min)
{
min = Tree->hafuman[i].wight;
index = i;
}
}
}
return index;
}

收获:让我对二叉搜索树和哈夫曼树有了真正意义上的区分和了解
二叉搜索树是倾向于每一个结点都有其对应信息,是用来存储信息,增删查改。
哈夫曼树是用于解码编码,而且只是研究根结点到叶子结点的权值。
共同点:都需要找到其最优二叉树。一般是左孩子小,右孩子大。

C数据结构:哈夫曼树算法实现与应用的更多相关文章

  1. 哈夫曼树算法及C++实现

    一.相关概念 1.叶子结点的权值(weight)是对叶子结点赋予的一个有意义的数值量. 2.设二叉树有n个带权值的叶子结点,从根节点到各个叶子结点的路径长度与相应叶子结点权值的乘积之和叫做二叉树的带权 ...

  2. 数据结构-哈夫曼树(python实现)

    好,前面我们介绍了一般二叉树.完全二叉树.满二叉树,这篇文章呢,我们要介绍的是哈夫曼树. 哈夫曼树也叫最优二叉树,与哈夫曼树相关的概念还有哈夫曼编码,这两者其实是相同的.哈夫曼编码是哈夫曼在1952年 ...

  3. C#数据结构-赫夫曼树

    什么是赫夫曼树? 赫夫曼树(Huffman Tree)是指给定N个权值作为N个叶子结点,构造一棵二叉树,若该树的带权路径长度达到最小.哈夫曼树(也称为最优二叉树)是带权路径长度最短的树,权值较大的结点 ...

  4. 数据结构-哈夫曼(Huffman)

    #include <iostream> #include <cstdio> #include <malloc.h> #define LIST_INIT_SIZE 1 ...

  5. Java数据结构和算法(四)赫夫曼树

    Java数据结构和算法(四)赫夫曼树 数据结构与算法目录(https://www.cnblogs.com/binarylei/p/10115867.html) 赫夫曼树又称为最优二叉树,赫夫曼树的一个 ...

  6. java 哈夫曼编码

    //哈夫曼树类 public class HaffmanTree { //最大权值 ; int nodeNum ; //叶子结点个数 public HaffmanTree(int n) { this. ...

  7. C++ 漫谈哈夫曼树

    1. 前言 什么是哈夫曼树? 把权值不同的n个结点构造成一棵二叉树,如果此树满足以下几个条件: 此 n 个结点为二叉树的叶结点 . 权值较大的结点离根结点较近,权值较小的结点离根结点较远. 该树的带权 ...

  8. 数据结构图文解析之:哈夫曼树与哈夫曼编码详解及C++模板实现

    0. 数据结构图文解析系列 数据结构系列文章 数据结构图文解析之:数组.单链表.双链表介绍及C++模板实现 数据结构图文解析之:栈的简介及C++模板实现 数据结构图文解析之:队列详解与C++模板实现 ...

  9. SDUT 3345 数据结构实验之二叉树六:哈夫曼编码

    数据结构实验之二叉树六:哈夫曼编码 Time Limit: 1000MS Memory Limit: 65536KB Submit Statistic Problem Description 字符的编 ...

  10. 【数据结构】赫夫曼树的实现和模拟压缩(C++)

    赫夫曼(Huffman)树,由发明它的人物命名,又称最优树,是一类带权路径最短的二叉树,主要用于数据压缩传输. 赫夫曼树的构造过程相对比较简单,要理解赫夫曼数,要先了解赫夫曼编码. 对一组出现频率不同 ...

随机推荐

  1. 6 CSS样式继承

    6 样式继承 CSS的样式表继承指的是,特定的CSS属性向下传递到子孙元素.总的来说,一个HTML文档就是一个家族,然后html元素有两个子元素,相当于它的儿子,分别是head和body,然后body ...

  2. #拓扑排序#洛谷 5157 [USACO18DEC]The Cow Gathering P

    题目 给出一棵树和一些限制关系 \((a_i,b_i)\), 一种合法的删点序列当且仅当删除一个点之后树的大小不超过 1 或不存在孤立点, 并且 \(a_i\) 要比 \(b_i\) 先删除,问 \( ...

  3. Jetty的http-forwarded模块

    启用http-forwarded模块,执行如下命令: java -jar $JETTY_HOME/start.jar --add-modules=http-forwarded 命令的输出,如下: IN ...

  4. 一文了解网络编程之走进TCP三次握手和HTTP那些你不知道的事

    受到很多引人入胜的标题党的影响,我终于决定,要起一个比他们还标题党的题目,打不过还不能加入吗,嘿嘿. 网络编程一直是我的弱项,其实归根结底还是我太懒了,一看到那个osi七层模型,TCP/IP模型还有那 ...

  5. 一种提升深度多视角行人检测的泛化性能的方法 Bringing Generalization to Deep Multi-View Pedestrian Detection

    一种提升深度多视角行人检测的泛化性能的方法 Bringing Generalization to Deep Multi-View Pedestrian Detection 论文url: https:/ ...

  6. HarmonyOS属性动画开发示例(ArkTS)

      介绍 利用ArkUI组件不仅可以实现属性变化引起的属性动画,也可以实现父组件状态变化引起子组件产生动画效果,这种动画为显式动画.效果如图所示: 相关概念 显式动画:提供全局animateTo显式动 ...

  7. How Python Handles Big Files

     The Python programming language has become more and more popular in handling data analysis and proc ...

  8. RestfulApi 学习笔记——查询与过滤还有搜索(五)

    前言 过滤和查询感觉是一个样子,实际上是不同含义.查询是查询一个主体,如果说要查询全部男职工但是名字中带良的,全部男职工 就是主体要查询的对象,然后名字中带良的表示的是过滤. 那么什么是搜索呢?搜索是 ...

  9. java中jar文件

    1.文档性质的jar文件 可以将有包名的类的字节码文件压缩成一个jar文件,供其他源文件用import语句导入jar文件中的类. 以下结合具体的两个类给出生成的jar文件的步骤eg23中TestTwo ...

  10. axios 使用与 拦截器

    未拦截使用使用: 由于axios每个请求都是异步.例如有ABC三个请求,C需要拿到AB请求回来的值作为参数,则需同步加载才能,所以使用axios.all才好完成.... 拦截器:为了处理axios中g ...