1. 哈夫曼编解码原理
霍夫曼编码(Huffman Coding)是一种编码方法,霍夫曼编码是可变字长编码(VLC)的一种。

霍夫曼编码使用变长编码表对源符号(如文件中的一个字母)进行编码,其中变长编码表是通过一种评估来源符号出现机率的方法得到的,出现机率高的字母使用较短的编码,反之出现机率低的则使用较长的编码,这便使编码之后的字符串的平均长度、期望值降低,从而达到无损压缩数据的目的。

霍夫曼编码的具体步骤如下:

  1. 将信源符号的概率按减小的顺序排队。
  2. 把两个最小的概率相加,并继续这一步骤,始终将较高的概率分支放在右边,直到最后变成概率1。
  3. 画出由概率1处到每个信源符号的路径,顺序记下沿路径的0和1,所得就是该符号的霍夫曼码字。
  4. 将每对组合的左边一个指定为0,右边一个指定为1(或相反)。

:现有一个由5个不同符号组成的30个符号的字符串:

BABACAC ADADABB CBABEBE DDABEEEBB

  • 首先计算出每个字符出现的次数(概率):
字符 次数
B 10
A 8
C 3
D 4
E 5
  • 把出现次数(概率)最小的两个相加,并作为左右子树,重复此过程,直到概率值为1

    第一次:将概率最低值3和4相加,组合成7:

    第二次:将最低值5和7相加,组合成12:

    第三次:将8和10相加,组合成18:

    第四次:将最低值12和18相加,结束组合:
  • 将每个二叉树的左边指定为0,右边指定为1。
  • 沿二叉树顶部到每个字符路径,获得每个符号的编码。
字符 次数 编码
B 10 11
A 8 10
C 3 010
D 4 011
E 5 00

我们可以看到出现次数(概率)越多的会越在上层,编码也越短,出现频率越少的就越在下层,编码也越长。当我们编码的时候,我们是按“bit”来编码的,解码也是通过bit来完成,如果我们有这样的bitset “10111101100″ 那么其解码后就是 “ABBDE”。所以,我们需要通过这个二叉树建立我们Huffman编码和解码的字典表。

这里需要注意的是,Huffman编码使得每一个字符的编码都与另一个字符编码的前一部分不同,不会出现像’A’:00, ’B’:001,这样的情况,解码也不会出现冲突。

霍夫曼编码的局限性
利用霍夫曼编码,每个符号的编码长度只能为整数,所以如果源符号集的概率分布不是2负n次方的形式,则无法达到熵极限;输入符号数受限于可实现的码表尺寸;译码复杂;需要实现知道输入符号集的概率分布;没有错误保护功能。

2.哈夫曼编解码实现(C++)

#include<iostream>
#include<string>
using namespace std;struct Node
{double weight;string ch;string code;int lchild, rchild, parent;
};void Select(Node huffTree[], int *a, int *b, int n)//找权值最小的两个a和b,且无父节点的两个节点合并
{int i;double weight = 0; //找最小的数for (i = 0; i < n; i++){if (huffTree[i].parent != -1)     //判断节点是否已经选过continue;else{if (weight == 0){weight = huffTree[i].weight;*a = i;}else{if (huffTree[i].weight < weight){weight = huffTree[i].weight;*a = i;}}}}weight = 0; //找第二小的数for (i = 0; i < n; i++){if (huffTree[i].parent != -1 || (i == *a))//排除已选过的数continue;else{if (weight == 0){weight = huffTree[i].weight;*b = i;}else{if (huffTree[i].weight < weight){weight = huffTree[i].weight;*b = i;}}}}//int temp;//if (huffTree[*a].weight > huffTree[*b].weight)  //小的数放左边//{// temp = *a;//   *a = *b;// *b = temp;//}
}void Huff_Tree(Node huffTree[], int w[], string ch[], int n)
{//初始过程 2倍的节点数for (int i = 0; i < 2 * n - 1; i++) {huffTree[i].parent = -1;huffTree[i].lchild = -1;huffTree[i].rchild = -1;huffTree[i].code = "";}for (int i = 0; i < n; i++){huffTree[i].weight = w[i];huffTree[i].ch = ch[i];}//构建哈夫曼树for (int k = n; k < 2 * n - 1; k++){int i1 = 0;int i2 = 0;Select(huffTree, &i1, &i2, k); //将i1,i2节点合成节点khuffTree[i1].parent = k;huffTree[i2].parent = k;huffTree[k].weight = huffTree[i1].weight + huffTree[i2].weight;huffTree[k].lchild = i1;huffTree[k].rchild = i2;}
}void Huff_Code(Node huffTree[], int n)
{int i, j, k;string s = "";for (i = 0; i < n; i++){s = "";j = i;while (huffTree[j].parent != -1) //从叶子往上找到根节点{k = huffTree[j].parent;if (j == huffTree[k].lchild) //如果是根的左孩子,则记为0{s = s + "0";}else{s = s + "1";}j = huffTree[j].parent;}cout << "字符 " << huffTree[i].ch << " 的编码:";for (int l = s.size() - 1; l >= 0; l--){cout << s[l];huffTree[i].code += s[l]; //保存编码}cout << endl;}
}string Huff_Decode(Node huffTree[], int n, string s)
{cout << "解码后为:";string temp = "", str = "";//保存解码后的字符串for (int i = 0; i < s.size(); i++){temp = temp + s[i];for (int j = 0; j < n; j++){if (temp == huffTree[j].code){str = str + huffTree[j].ch;temp = "";break;}else if (i == s.size() - 1 && j == n - 1 && temp != "")//全部遍历后没有{str = "解码错误!";}}}return str;
}int main()
{//编码过程const int n = 5;Node huffTree[2 * n];string str[] = { "A", "B", "C", "D", "E" };int w[] = { 8, 10, 3, 4, 5 };Huff_Tree(huffTree, w, str, n);Huff_Code(huffTree, n);//解码过程string s;cout << "输入编码:";cin >> s;cout << Huff_Decode(huffTree, n, s) << endl;;system("pause");return 0;
}

结果:


以上博文整理自:

  1. 理论部分:https://www.cnblogs.com/gyk666/p/6851821.html
  2. 实现部分:https://blog.csdn.net/xgf415/article/details/52628073

哈夫曼编解码原理与实现【转载】相关推荐

  1. 贪心算法简单实践 -- 分糖果、钱币找零、最多区间覆盖、哈夫曼编解码

    1. 贪心算法概览 贪心算法是一种算法思想.希望能够满足限制的情况下将期望值最大化.比如:Huffman编码,Dijkstra单源最短路径问题,Kruskal最小生成树 等问题都希望满足限制的情况下用 ...

  2. labview霍夫曼编码_哈夫曼编解码压缩解压文件—C++实现

    前言 哈夫曼编码是一种贪心算法和二叉树结合的字符编码方式,具有广泛的应用背景,最直观的是文件压缩.本文主要讲述如何用哈夫曼编解码实现文件的压缩和解压,并给出代码实现. 哈夫曼编码的概念 哈夫曼树又称作 ...

  3. 哈夫曼编解码(C语言)

    哈夫曼编解码(C语言) 示例 输入: helllllllo 生成码表: a:00010010 b:00010011 c:00010100 d:00010101 e:001 f:00010110 g:0 ...

  4. 数据结构与算法之霍夫曼编码解码实现

    目标:将字符串"can you can a can as a can canner can a can."编码再解码 流程: 将字符串转成bytes (byte[]格式)(eg.[ ...

  5. 哈夫曼编/译码器(Huffman)

    [问题描述] 打开一篇英文文章,统计该文章中每个字符出现的次数,然后以它们作为权值,设计一个哈夫曼编/译码系统. [基本要求]     以每个字符出现的次数为权值,建立哈夫曼树,求出哈夫曼编码, 对文 ...

  6. 赫夫曼树的原理和构建

    赫夫曼树的原理和构建 1. 赫夫曼树的构造 给定N个权值分别为w1, w2, -, Wn的节点.构造赫夫曼树的算法描述如下: ​ 1)将这N个结点分别作为N棵树仅含一个结点的二叉树,构成森林F. ​ ...

  7. 数据结构哈夫曼编码解码课程设计

    数据结构课程设计 源代码在另一篇博客可以找到:https://blog.csdn.net/qq_40513633/article/details/85055411?ops_request_misc=% ...

  8. 哈夫曼编码解码课程设计源代码

    数据结构课程设计 "哈夫曼编码/译码器 设计一个利用哈夫曼算法的编码和译码系统,重复显示并处理以下项目,知道选择退出为止/ [基本要求] 1)将权值数据存放在数据文件(文件名data.txt ...

  9. yolov5的anchors及bbox的编解码原理

    yolov5的anchors的编解码原理 yolov5的anchors及bbox的编解码原理 1.anchor的生成 1)base anchor的生成 2)base anchor的平移和复制 2.bb ...

最新文章

  1. 给VMWare虚拟机做快照--保存你的劳动成果
  2. Unity屏幕射线碰撞
  3. unknown bottom blob ‘data‘ (layer ‘data_fixed‘, boblob ‘data‘ (layer ‘data_fixed‘, bottom index 0)
  4. html页面选择指定条件在下方显示,如何从符合特定条件的HTML中找到CSS选择器?...
  5. 浅谈 CTR 预估模型发展史
  6. linux crontab工作日志,linux使用crontab执行定时任务
  7. P4211 [LNOI2014]LCA(离线 + 在线 做法)
  8. 移动路线(信息学奥赛一本通-T1194)
  9. React与ES6(一)开篇介绍
  10. C++中的struct与class继承方式
  11. 版本产品_飞书首次举办产品发布会 新版本“π”正式发布
  12. Google推荐的15条军规:HTML5代码规范
  13. 练习:将从表读出来的时间戳除以1000(java读时间戳会多出3个000)用jackson包 实现...
  14. php手机下载功能,phpwind手机客户端1.2版主要功能亮点详解
  15. 人工智能-基于规则的专家系统(基础知识)
  16. 工作站安装Ubuntu,显卡驱动,pytorch全流程
  17. C/C++音乐播放(亲测有效)
  18. 科幻3D场景必备要素—地球篇
  19. 要学习使用的安全工具
  20. 【国信长天蓝桥杯】扩展板⑦ 光敏电阻的使用

热门文章

  1. MAC OS 烧录ISO文件到U盘
  2. Nginx stream模块初探
  3. Oracle备份与恢复 关于expdp导出远程数据到本地的使用
  4. Linux 查看网段内所有IP
  5. 修改oracle实例名orcl为demo
  6. Hibernate Session merge,update,save,saveOrUpdate,persist
  7. c语言两个线程交替打印奇数和偶数,经典面试题——两个线程交替打印奇数和偶数...
  8. vue.js视频课程_在此免费课程中学习Vue.js! ✨
  9. iphone 2x 3x_iPhone X的未来:从现实到荒诞
  10. docker下使用solr