数据结构与算法--哈夫曼树及其应用
一、哈夫曼树的基本概念
1) 路径: 从树中一个结点到另一个结点之间的分支构成这两个结点间的路径
2) 结点的路径长度: 两结点间路径上的分支数
3) 树的路径长度:从树根到每一个结点的路径长度之和;记作TL
4) 结点数目相同的二叉树中,完全二叉树是路径长度最短的二叉树
5) 权: 将树中结点赋给一个有着某种含义的数值,则这个数值称为该结点的权
6) 结点的带权路径长度:从根结点到该结点之间的路径长度与该结点的权的乘积
7) 树的带权路径长度(WPL): 树中所有叶子结点的带权路径长度之和
8) 哈夫曼树: 带权路径长度最短的树
//"带权路径长度最短"是在"度相同"的树中比较而得的结果,因此有最优二叉树、最优三叉树之称等等
9) 哈夫曼树-最优二叉树: 带权路径长度最短的二叉树
二、哈夫曼树的构造算法
贪心算法: 构造哈夫曼树时首先选择权值小的叶子结点
1.哈夫曼树算法(构造哈夫曼树的方法)
1) 根据n个给定的权值{W1,W2,...,Wn}构成n棵二叉树的森林F={T1,T2,...,Tn},其中Ti只有一个带权为Wi的根结点
//构造森林全是根
2) 在F中选取两棵根结点的权值最小的树作为左右子树,构造一棵新的二叉树,
且设置新的二叉树的根结点的权值为其左右子树上根结点的权值之和
//选用两小造新树
3) 在F中删除这两棵树,同时将新得到的二叉树加入森林中
//删除两小添新人
4) 重复2)和3),直到森林中只有一棵树为止,这棵树即为哈夫曼树
//重复23剩单根
三、哈夫曼树构造算法实现
1.采用顺序存储结构(链式也行)-----一维结构数组
typedef struct //结点类型定义
{int weight; //权值int parent, lch, rch; //双亲结点、左孩子及右孩子下标
}HTNode,*HuffmanTree;
哈夫曼树中的结点下标i | weight | parent | lch | rch |
---|---|---|---|---|
1 | ||||
2 | ||||
3 | ||||
4 | ||||
... | ||||
... | ||||
2n-1 |
2.初始化数组并建立哈夫曼树
void Select(HuffmanTree HT,int n,int *s1,int *s2)
{*s1 = *s2 = 0;int min1 = INT_MAX; //最小值,INT_MAX在<limits.h>中定义int min2 = INT_MAX; //次小值for (int i = 1; i <= n; i++){if (HT[i].parent == 0) //筛选没有双亲的最小和次小值下标{if (HT[i].weight < min1) //如果比最小值小{min2 = min1;*s2 = *s1;min1 = HT[i].weight;*s1 = i;}else if((HT[i].weight >= min1) && (HT[i].weight < min2)) //如果大于等于最小值且小于次小值{min2 = HT[i].weight;*s2 = i;}else //如果大于次小值则什么也不做{;}}}
}void CreatHuffmanTree(HuffmanTree HT, int n) //初始化数组并建立哈夫曼树
{if (n <= 1)return;int m = 2 * n - 1; //数组共2n-1个元素HT = (HuffmanTree)malloc((m + 1) * sizeof(HTNode)); //0号单元不用,HT[m]表示根结点for (int i = 1; i <= m; i++) //将2n-1个元素的parent,lch,rch设置为0{HT[i].parent = 0;HT[i].lch = 0;HT[i].rch = 0;}for (int i = 1; i <= n; i++) //输入前n个元素的weight值{scanf("%d", &HT[i].weight);}for (int i = n + 1; i <= m; i++) //合并产生n-1个结点----构造Huffman树{ Select(HT, i - 1, &s1, &s2); //在HT[k](1<=k<=i-1)中选择两个其双亲为0,//且权值最小的结点下标存在s1,s2中HT[s1].parent = i; //从F中删除s1HT[s2].parent = i; //从F中删除s1HT[i].lch = s1;HT[i].rch = s2; //s1,s2分别作为i的左右孩子HT[i].weight = HT[s1].weight + HT[s2].weight; //i的权值为左右孩子权值之和}
}
四、哈夫曼编码思想(哈夫曼编码是最优前缀码)
1) 统计字符集中每个字符在电文中出现的平均频率(概率越大,要求编码越短)
2) 利用哈夫曼树的特点:权越大的叶子离根越近;将每个字符的概率值作为权值,构造哈夫曼树,则概率越大的结点,路径越短
3) 在哈夫曼树的每个分支上标上0或1:
结点的左分支标0,右分支标1
把从根到每个叶子的路径上的标号连接起来,作为该叶子代表的字符的编码
1.为什么哈夫曼编码能够保证是前缀编码?
因为没有一片树叶是另一片树叶的祖先,所以每个叶结点的编码就不可能是其它叶结点编码的前缀
2.为什么哈夫曼树编码能够保证字符编码总长最短?
因为哈夫曼树的带权路径长度最短,故字符编码的总长最短
五、哈夫曼编码的算法实现
void CreateHuffmanCode(HuffmanTree HT, HuffmanCode *HC, int n) //从叶子到根逆向求每个字符的哈夫曼编码,存储在编码表HC中
{*HC = (char**)malloc((n + 1)*sizeof(char *)); //分配n个字符编码的头指针char *cd = (char *)malloc(n * sizeof(char)); //分配临时存放编码的动态数组空间cd[n - 1] = '\0'; //编码结束符for (int i = 1; i <= n; i++) //逐个字符求哈夫曼编码{int start = n - 1;int c = i;int f = HT[i].parent;while (f != 0) //从叶子结点开始向上回溯,直到根结点{--start; //回溯一次start向前指一个位置if (HT[f].lch == c) //结点c是f的左孩子,则生成代码0cd[start] = '0'; else //结点c是f的右孩子,则生成代码1cd[start] = '1';c = f;f = HT[f].parent; //继续向上回溯} //求出第i个字符的编码(*HC)[i] = (char*)malloc((n - start) * sizeof(char)); //为第一个字符串编码分配空间strcpy((*HC)[i], &cd[start]); //将求得的编码从临时空间cd复制到HC的当前行中}free(cd); //释放临时空间
}
六、文件的编码和解码
1.编码
1) 输入各字符及其权值
2) 构造哈夫曼树----HT[i]
3) 进行哈夫曼编码---HC[i]
4) 查HC[i],得到各字符的哈夫曼编码
2.解码
1) 构造哈夫曼树
2) 依次读入二进制码
3) 读入0,则走向左孩子;读入1,则走向右孩子
4) 一旦到达某叶子时,即可译出字符
5) 然后再从根出发继续译码,直到结束
数据结构与算法--哈夫曼树及其应用相关推荐
- 数据结构与算法 / 霍夫曼树、霍夫曼编码和解码
一. 诞生原因 找出存放一串字符所需的最少的二进制编码. 二. 构造方法 首先统计出每种字符出现的频率,即:概率.权值. 例如:频率表 A:60, B:45, C:13 D:69 E ...
- 数据结构与算法——赫夫曼树基本实现
目录 一.赫夫曼树 1.1 基本介绍 1.2 赫夫曼树创建步骤图解 1.3 代码实现 二.赫夫曼编码 2.1 基本介绍 2.1.1 通讯领域 - 定长编码 - 举例说明 2.1.2 通讯领域 - ...
- 数据结构与算法(赫夫曼树,赫夫曼编码)
赫夫曼树 基本介绍: (1)给定n个权值作为n给叶子节点,构造一棵二叉树,若该树的带权路径长度(wpl)达到最小,称这样的二叉树为最优二叉树,也称哈夫曼树(HuffmanTree),还有的树翻译为霍夫 ...
- 数据结构与算法--哈夫曼树应用
第1关:统计报文中各个字符出现的次数 任务描述 本关任务: 给定一串文本,统计其中各个字符出现的次数: 测试说明 平台会对你编写的代码进行测试: 测试输入:` abcdeabcdeabcdabcdab ...
- 数据结构实验之——哈夫曼树的实现
数据结构实验之--哈夫曼树的实现 目录 说明 代码 测试用例 目录 说明 哈夫曼树的这个实验我是采用常用的左'0'右'1'来实现的,输入是用文本输入的,大家在用之前目录下要记得创建"HT.t ...
- 数据结构学习记录——哈夫曼树(什么是哈夫曼树、哈夫曼树的定义、哈夫曼树的构造、哈夫曼树的特点、哈夫曼编码)
目录 什么是哈夫曼树 哈夫曼树的定义 哈夫曼树的构造 图解操作 代码实现 代码解析 哈夫曼树的特点 哈夫曼编码 不等长编码 二叉树用于编码 哈夫曼编码实例 什么是哈夫曼树 我们先举个例子: 要将百分制 ...
- 数据结构实验——基于哈夫曼树的数据压缩算法
/* 注:输入为多行字符串,以"0"结尾:例:abc def 0 此程序无法执行由单个字符组成的字符串. */ #include<iostream> #include& ...
- 【数据结构Note5】-哈夫曼树
文章目录 哈夫曼树 1. 构造哈夫曼树 2. 哈夫曼树的性质 3. 哈夫曼编码 哈夫曼树 结点的权:有某种显示含义的数值(如:表示结点的重要性等) 结点的带权路径长度:从树的根到该结点的路径长度(经过 ...
- 【数据结构-N】哈夫曼树带权路径计算
那个闪闪发光的人 会在某一天的雨后,不经意地出现在你的迷茫路口. 目录: 哈夫曼树的构建 带权路径长度计算 >>构建 哈夫曼树,又称最优二叉树,是一类带权路径长度最短的树. 构建哈夫曼树的 ...
最新文章
- Media Player网页播放音频,视频,图片总汇
- string:值类型?引用类型?[转]
- 操作系统原理之I/O设备管理(第六章上半部分)
- codeforces 337D Book of Evil(dp)
- php元素浮动会产生哪些影响,css浮动带来什么问题
- 第一条Pulsar消息发送
- 高可用,完全分布式Hadoop集群HDFS和MapReduce安装配置指南
- hystrix熔断器之command实现
- 读书笔记——《灰度决策:如何处理复杂、棘手、高风险的难题》
- python读取tiff文件_怎么用python读取和写入TIFF文件1
- pdf打印机如何加入背景
- 【JavaScript设计模式】装饰器模式
- R如何导入带有分隔符号的文件
- 【第38题】2019年OCP认证12C题库062考试最新考试原题
- 「Prompt」是什么,并用简单的范例让你了解如何善用他、避开陷阱,以此获得更好的 ChatGPT 回复。
- [从零开始]用python制作识图翻译器·四
- JAVA算法:给定两个整数 n 和 k,返回 1 ... n 中所有可能的 k 个数的组合(JAVA)
- 【店小蜜】基础介绍-全自动模式
- EXCEL函数篇之一文读懂VLOOKUP精准查找、近似查找、模糊查找的区别
- Google Play 签名不一致的解决方案
热门文章
- 【码农开店连载记】-- 0 开坑啦
- 创新朋友圈植入广告,享受精准的朋友圈营销
- 塔塔露也能学会的算法(2) | 我有背包你有手么
- 什么是JAVA?JAVA能用来干什么?
- 使用requests爬虫制作自己的天气预报“Api”
- The tomcat server configuration at /sever/tomcat v9.0 localhost-config is.......错误解析
- 上海交大 计算机科学家,世界顶尖科学家论坛丨上海交大计算机系教授俞凯:科研经费支持应少些“风险意识”...
- 宠物医院小程序开发,轻松引流
- 第1章 开篇-为什么要做CI/CD?
- 如何在iis中设置可以在网页上面直接下载安卓app并自动安装