数据结构实验代码分享 - 3 (哈夫曼树 / HuffmanTree)
哈夫曼编码/ 译码系统(树应用)
[问题描述]
任意给定一个仅由 26 个大写英文字母组成的字符序列,根据哈夫曼编码算法,求得每个字符的哈夫曼编码。
要求:
1)输入一个由 26 个英文字母组成的字符串,请给出经过哈夫曼编码后的编码序列及其编码程度。(编码)
2)采用上一问题的哈夫曼编码,给定一串编码后的序列,将其翻译为原字符序列。(解码)
样例:
输入原串:CASBCATBSATBAT
输出:
A 00
B 10
T 11
C 010
S 011
输入:0100011
输出:CAT
设计思路
自顶向下拆解:
1. 编码部分(Encode)
a) 输入字符串;
b) 根据输入的字符串创建HuffmanTree;
c) 遍历HuffmanTree 得到各结点的HuffmanCode;
d) 收集各个叶节点的字符及其HuffmanCode,做成HuffmanCodeTable并输出。
注:由HuffmanTree的构造方法可知:叶节点 <=> “有效字符”
2. 译码部分(Decode)
a) 输入密文字符串;
b) 在HuffmanCodeTable中逐字匹配以找到明文字符 / 或是直接遍历HuffmanTree即可;
c) 输出明文字符串。
思维导图如下:

代码实现
两个类:

1 class HuffmanTNode // 用于Encode时的HuffmanTree
2 {
3 public:
4 char ch; // 字符
5 int weight; // 权值、频次
6 HuffmanTNode* lchild;
7 HuffmanTNode* rchild;
8 string HuffmanCode;
9
10 HuffmanTNode() : HuffmanCode(), lchild(nullptr), rchild(nullptr) {}
11 HuffmanTNode(char a, int wei) : ch(a), weight(wei), HuffmanCode(), lchild(nullptr), rchild(nullptr) {}
12 HuffmanTNode(const HuffmanTNode &other) : ch(other.ch), weight(other.weight), HuffmanCode(other.HuffmanCode),
13 lchild(other.lchild), rchild(other.rchild) {}
14 ~HuffmanTNode() {
15 // 对左右子树的递归清理
16 if (lchild != nullptr) {
17 delete lchild;
18 }
19 lchild = nullptr;
20 if (rchild != nullptr) {
21 delete rchild;
22 }
23 rchild = nullptr;
24 }
25 };
26
27 class HuffmanCharAndCode // 用于Decode时的查找表
28 {
29 public:
30 char ch; // 字符
31 string HuffmanCode; // 哈夫曼编码
32
33 HuffmanCharAndCode() {}
34 HuffmanCharAndCode(char a, const string &code) : ch(a){
35 HuffmanCode += code;
36 }
37 ~HuffmanCharAndCode() {}
38 };
包装类 * 2
Encode:
1. main() 函数展示了程序的主干,如下:

1 int main() {
2
3 /*************************ENCODE*************************/
4 // 1 输入字符串
5 printf("ENCODE: \n");
6 string str;
7 printf("plz Enter String :");
8 std::cin >> str;
9
10 // 2 根据输入的字符串创建HuffmanTree
11 HuffmanTNode* root = CreateHuffmanTree(str);
12 while (root == nullptr) { // 非法输入字符串的处理
13 printf("\nERROR! Invalid Input!\n");
14 printf("plz Enter String Again :");
15 std::cin >> str;
16 root = CreateHuffmanTree(str);
17 }
18
19 // 3 根据生成的HuffmanTree得到HuffmanCodeTable
20 vector<char> vec_code;
21 GetHuffmanCode(root, vec_code);
22 vector<HuffmanCharAndCode*> HuffmanCodeTable;
23 GetHuffmanCodeTable(root, HuffmanCodeTable);
24
25 // 4 输出字符及其对应的HuffmanCode
26 printf("\nSUCCESS! the HuffmanCode is listed as below: \n");
27 std::sort(HuffmanCodeTable.begin(), HuffmanCodeTable.end(), compare_CodeTable);
28 OutputHuffmanCode(HuffmanCodeTable);
29
30 /*************************DECODE*************************/
31
32 // 1 输入密文字符串
33 printf("\nDECODE: \n");
34 string ciphertext;
35 printf("plz Enter CipherText :");
36 std::cin >> ciphertext;
37
38 // 2 解码密文字符串得到明文
39 string cleartext;
40 int error_index = 1;
41 while (HuffmanDecode(ciphertext, HuffmanCodeTable, cleartext, error_index) == false) { // 非法密文字符串的处理
42 printf("\nERROR! Invalid Input Ciphertext!\n");
43 printf("\nthe POTENTIAL index of error char in at: %d\n", error_index);
44 printf("plz Enter CipherText Again :");
45 std::cin >> ciphertext;
46 }
47
48 // 3 输出明文字符串
49 printf("SUCCESS! the ClearText is: \n");
50 std::cout << cleartext << std::endl;
51
52 // 释放HuffmanTable
53 for (HuffmanCharAndCode* elem : HuffmanCodeTable) {
54 delete elem;
55 }
56
57 system("pause");
58 return 0;
59 }
main()
2. 创建HuffmanTree(),如下:

1 HuffmanTNode* CreateHuffmanTree(const string &str) {
2 // 字符串检查
3 if (str.size() == 0) { return nullptr; }
4 // 字符频次记录桶
5 vector<HuffmanTNode*> bucket;
6 // 填充字符频次记录桶
7 if (FillCharFrequencyBucket(str, bucket) == false) { return nullptr; }
8 // 若只有一个字符 那么没必要用哈夫曼编码
9 if (bucket.size() == 1) { return nullptr; }
10
11
12 // 当bucket中只剩下一个元素,那么它就是HuffmanTree的root
13 while (bucket.size() != 1) {
14 // 令bucket中元素按weight非递增排序
15 std::sort(bucket.begin(), bucket.end(), compare_bucket);
16
17 // 从bucket中取两个最小的elem
18 HuffmanTNode *elem_1 = bucket[bucket.size() - 1]; bucket.pop_back();
19 HuffmanTNode *elem_2 = bucket[bucket.size() - 1]; bucket.pop_back();
20 // 根据 elem1 与 elem2 的weight 得到它俩的 root
21 HuffmanTNode *root_tmp = new HuffmanTNode('\0', elem_1->weight + elem_2->weight);
22 // root_tmp, elem_1, elem_2 三者组成三结点的二叉树
23 root_tmp->lchild = elem_2;
24 root_tmp->rchild = elem_1;
25
26 // root_tmp 入桶
27 bucket.push_back(root_tmp);
28 }
29
30 // bucket中最后元素,就是哈夫曼树的根节点指针
31 HuffmanTNode *root = bucket[0];
32 return root;
33 }
CreateHuffmanTree()
3. 遍历得到各结点HuffmanCode,再收集各个叶节点的Code即可,我就只放前者吧,稍微有趣一点,如下:

1 // 将vec_code中的字符转为字符串 并赋给当前节点curr->HuffmanCode
2 void visit(HuffmanTNode *curr, const vector<char> &vec_code) {
3 string Code(vec_code.begin(), vec_code.end());
4 curr->HuffmanCode = Code;
5 }
6
7 // (前序遍历改) 得到HuffmanTree上每个结点的HuffmanCode
8 void GetHuffmanCode(HuffmanTNode *root, vector<char> vec_code) {
9 if (root != nullptr) {
10 visit(root, vec_code);
11 vec_code.push_back('0');
12 GetHuffmanCode(root->lchild, vec_code);
13 vec_code.pop_back();
14 vec_code.push_back('1');
15 GetHuffmanCode(root->rchild, vec_code);
16 vec_code.pop_back();
17 }
18 }
先序遍历改,得各结点的HuffmanCode
Decode:
好像不是很难,就不放了,照着思路往下做就行。(主要我写的不是很好看...)
运行结果

ps: HuffmanCode不是唯一的,是根据你生成的HuffmanTree 和 你定义的Code规则而定,比如说我的Code规则是左0右1。
行,那就先这样吧,这代码写了好久都有些遗忘了,幸好之前做了思维导图,希望能帮助到你。
数据结构实验代码分享 - 3 (哈夫曼树 / HuffmanTree)的更多相关文章
- 数据结构图文解析之:哈夫曼树与哈夫曼编码详解及C++模板实现
0. 数据结构图文解析系列 数据结构系列文章 数据结构图文解析之:数组.单链表.双链表介绍及C++模板实现 数据结构图文解析之:栈的简介及C++模板实现 数据结构图文解析之:队列详解与C++模板实现 ...
- Java数据结构(十二)—— 霍夫曼树及霍夫曼编码
霍夫曼树 基本介绍和创建 基本介绍 又称哈夫曼树,赫夫曼树 给定n个权值作为n个叶子节点,构造一棵二叉树,若该树的带权路径长度(wpl)达到最小,称为最优二叉树 霍夫曼树是带权路径长度最短的树,权值较 ...
- 数据结构之C语言实现哈夫曼树
1.基本概念 a.路径和路径长度 若在一棵树中存在着一个结点序列 k1,k2,……,kj, 使得 ki是ki+1 的双亲(1<=i<j),则称此结点序列是从 k1 到 kj 的路径. 从 ...
- 数据结构-二叉树(6)哈夫曼树(Huffman树)/最优二叉树
树的路径长度是从树根到每一个结点的路径长度(经过的边数)之和. n个结点的一般二叉树,为完全二叉树时取最小路径长度PL=0+1+1+2+2+2+2+… 带权路径长度=根结点到任意结点的路径长度*该结点 ...
- (哈夫曼树)HuffmanTree的java实现
参考自:http://blog.csdn.net/jdhanhua/article/details/6621026 哈夫曼树 哈夫曼树(霍夫曼树)又称为最优树. 1.路径和路径长度在一棵树中,从一个结 ...
- javascript实现数据结构: 树和二叉树的应用--最优二叉树(赫夫曼树),回溯法与树的遍历--求集合幂集及八皇后问题
赫夫曼树及其应用 赫夫曼(Huffman)树又称最优树,是一类带权路径长度最短的树,有着广泛的应用. 最优二叉树(Huffman树) 1 基本概念 ① 结点路径:从树中一个结点到另一个结点的之间的分支 ...
- 哈夫曼树(三)之 Java详解
前面分别通过C和C++实现了哈夫曼树,本章给出哈夫曼树的java版本. 目录 1. 哈夫曼树的介绍 2. 哈夫曼树的图文解析 3. 哈夫曼树的基本操作 4. 哈夫曼树的完整源码 转载请注明出处:htt ...
- 哈夫曼树(二)之 C++详解
上一章介绍了哈夫曼树的基本概念,并通过C语言实现了哈夫曼树.本章是哈夫曼树的C++实现. 目录 1. 哈夫曼树的介绍 2. 哈夫曼树的图文解析 3. 哈夫曼树的基本操作 4. 哈夫曼树的完整源码 转载 ...
- 哈夫曼树(一)之 C语言详解
本章介绍哈夫曼树.和以往一样,本文会先对哈夫曼树的理论知识进行简单介绍,然后给出C语言的实现.后续再分别给出C++和Java版本的实现:实现的语言虽不同,但是原理如出一辙,选择其中之一进行了解即可.若 ...
- poj3253 Fence Repair【哈夫曼树+优先队列】
Description Farmer John wants to repair a small length of the fence around the pasture. He measures ...
随机推荐
- npm install --legacy-peer-deps 安装出现依赖包冲突的解决方案
npm install --legacy-peer-deps 安装出现依赖包冲突的解决方案 为什么 在安装依赖包的时候,会有依赖包的冲突 比如A包引用了C的1.0版本 B包依赖了C的1.1版本 win ...
- FastGithub.UI64位中文版V2.1.4绿色版 - 软件推荐
推荐理由 相对于改hosts,这个更好用 FastGithub.UI64位中文版V2.1.4绿色版 https://www.cr173.com/soft/670733.html
- 微信自动信息发送助手WMR
某信自动信息发送助手WMR 最近放假闲来无事,捣鼓了一下pyqt5,正好手上有每天定时大量群发消息的需求,正好就用pyqt5做个小应用练练手. 包含到的主要库:pyqt5.pyperclip.pyau ...
- 在Linux平台使用wps卡顿现象解决方法
是因为软件占据的内存过多,需要关掉目前不使用的软件,以释放系统内存.
- ElasticSearch 准实时原理
Elasticsearch 是一个基于 Lucene 库的搜索引擎.它提供了一个准实时的.分布式.支持多租户的全文搜索引擎. ----维基百科 那么问题来了,为啥 Elasticsearch 不是实时 ...
- vim下删除swp文件
vim下删除swp文件 几个选项的内涵 [O]pen Read-Only 只读的方式打开 (E)dit anyway 编辑模式打开,但是不会载入存盘的内容 (R)ecover 编辑模式打开并且加载暂存 ...
- 01.Android线程池实践基础
目录介绍 01.实际开发问题 02.线程池的优势 03.ThreadPoolExecutor参数 04.ThreadPoolExecutor使用 05.线程池执行流程 06.四种线程池类 07.exe ...
- 面试官:小伙子知道synchronized的优化过程吗?我:嘚吧嘚吧嘚,面试官:出去!
写在开头 面试官:小伙子,多线程中锁用过吗? 我:那是自然! 面试官:那你知道synchronized的优化吗? 我:synchronized作为重锁,开销大,在早期不被推荐使用,后期进行了优化,至于 ...
- vscode中Vetur插件关闭组件自动导入路径
vscode配置项中加入 "vetur.completion.autoImport": false, 或者,将图中4处勾去掉即可
- KingbaseES V8R6集群运维案例--主库PITR恢复后备库无法连接到集群
案例说明: KingbaseES V8R6集群,在主库执行PITR恢复后,clone备库:但是启动集群后,备库无法连接到主库,流复制状态和集群节点状态异常. 适用版本: KingbaseES V8R6 ...