一开始我用的三叉链表来生成哈夫曼编码,这一点都不递归。后来我想起了一度被递归统治地恐惧,我发现哈夫曼树不仅编码可以简单的用递归来求,树的WPL也可以。

改善后的递归版本如下,虽然WPL也可以通过递归来求,但我觉得当前的方法更好理解。

  1 #include <iostream>
  2 #include <vector>
  3 #include <stack>
  4 #include <string>
  5 #include <algorithm>
  6
  7 using std::cin;
  8 using std::cout;
  9 using std::endl;
 10 using std::vector;
 11 using std::sort;
 12 using std::string;
 13
 14 float WPL = 0.0f;
 15
 16 //二叉链表存储结构
 17 struct _WEIGHTNODE {
 18     float weight;
 19     char value;
 20     struct _WEIGHTNODE *ptrLeft, *ptrRight;
 21
 22     _WEIGHTNODE(char _input, float _W) {
 23         weight = _W;
 24         value = _input;
 25         ptrLeft = ptrRight = nullptr;
 26     }
 27
 28     _WEIGHTNODE() {
 29         weight = 0.0f;
 30         value = '?';
 31         ptrLeft = ptrRight = nullptr;
 32     }
 33
 34     //重载输出流
 35     friend std::ostream &operator<<(std::ostream &output, struct _WEIGHTNODE const *NODE) {
 36         return output << "Value : " << NODE->value << " --- Weight : " << NODE->weight;
 37     }
 38 };
 39
 40 typedef struct _WEIGHTNODE NODE;
 41
 42 //用于排序
 43 bool compareWeight(const NODE *n1, const NODE *n2) {
 44     return n1->weight < n2->weight;
 45 }
 46
 47 //递归求编码
 48 void HuffmanCode(NODE *root, string code) {
 49     if (root) {
 50         if (root->value != '#') {
 51             cout << root->value << " : " << code << endl;
 52             WPL += root->weight * code.length();
 53         }
 54         HuffmanCode(root->ptrLeft, code + "0");
 55         HuffmanCode(root->ptrRight, code + "1");
 56     }
 57 }
 58
 59 int main() {
 60     //存放二叉树的顶点
 61     vector<NODE *> TotalValues;
 62     float inputWeight;
 63     char inputValue;
 64     //输入数据,遇到问号就停止
 65     while (cin >> inputValue >> inputWeight) {
 66         if (inputWeight < 0 || inputValue == '?') {
 67             break;
 68         }
 69         TotalValues.push_back(new NODE(inputValue, inputWeight));
 70     }
 71
 72     //遍历所有输入的节点并打印
 73     for (auto EachMember : TotalValues) {
 74         cout << EachMember << endl;
 75     }
 76     cout << endl << "=== Huffman Code ===" << endl;
 77
 78     //根据已有节点创建Huffman Tree
 79     while (TotalValues.size() > 1) {
 80         //从小到大排序
 81         sort(TotalValues.begin(), TotalValues.end(), compareWeight);
 82
 83         //将权重最小的两个点提出
 84         NODE *tmp1 = *TotalValues.begin();
 85         TotalValues.erase(TotalValues.begin());
 86
 87         NODE *tmp2 = *TotalValues.begin();
 88         TotalValues.erase(TotalValues.begin());
 89
 90         //合成新节点再放回去
 91         NODE *CombinedNode = new NODE('#', tmp1->weight + tmp2->weight);
 92         CombinedNode->ptrLeft = tmp1;
 93         CombinedNode->ptrRight = tmp2;
 94
 95         TotalValues.push_back(CombinedNode);
 96     }
 97
 98     HuffmanCode(*TotalValues.begin(), "");
 99
100     cout << endl << "WPL : " << WPL << endl;
101
102     return 0;
103 }

以前的那个自作聪明的版本如下

  1 #include <iostream>
  2 #include <vector>
  3 #include <stack>
  4 #include <string>
  5 #include <algorithm>
  6
  7 using std::cin;
  8 using std::cout;
  9 using std::endl;
 10 using std::vector;
 11 using std::sort;
 12 using std::string;
 13
 14 //三叉链表存储结构
 15 struct _WEIGHTNODE {
 16     float weight;
 17     char value;
 18     struct _WEIGHTNODE *ptrLeft, *ptrRight, *ptrParent;
 19
 20     _WEIGHTNODE(char _input, float _W) {
 21         weight = _W;
 22         value = _input;
 23         ptrLeft = ptrRight = ptrParent = nullptr;
 24     }
 25
 26     _WEIGHTNODE() {
 27         weight = 0.0f;
 28         value = '?';
 29         ptrLeft = ptrRight = ptrParent = nullptr;
 30     }
 31
 32     //重载输出流
 33     friend std::ostream &operator<<(std::ostream &output, struct _WEIGHTNODE const *NODE) {
 34         return output << "Value : " << NODE->value << " --- Weight : " << NODE->weight;
 35     }
 36 };
 37
 38 typedef struct _WEIGHTNODE NODE;
 39
 40 //通过先序遍历得到当前二叉树的所有叶子节点
 41 void GetLeaf(NODE *root, vector<NODE *> &leaf) {
 42     if (root) {
 43         if (root->value != '#') {
 44             leaf.push_back(root);
 45         }
 46         GetLeaf(root->ptrLeft, leaf);
 47         GetLeaf(root->ptrRight, leaf);
 48     }
 49 }
 50
 51 //用于排序
 52 bool compareWeight(const NODE *n1, const NODE *n2) {
 53     return n1->weight < n2->weight;
 54 }
 55
 56 bool compareAlphabet(const NODE *n1,const NODE *n2) {
 57     return n1->value < n2->value;
 58 }
 59
 60 int main() {
 61     //存放二叉树的顶点
 62     vector<NODE *> TotalValues;
 63     float inputWeight;
 64     char inputValue;
 65     //输入数据,遇到问号就停止
 66     while (cin >> inputValue >> inputWeight) {
 67         if (inputWeight < 0 || inputValue == '?') {
 68             break;
 69         }
 70         TotalValues.push_back(new NODE(inputValue, inputWeight));
 71     }
 72
 73     //遍历所有输入的节点并打印
 74     for (auto EachMember : TotalValues) {
 75         cout << EachMember << endl;
 76     }
 77     cout << endl << "=== Huffman Code ===" << endl;
 78
 79     //根据已有节点创建Huffman Tree
 80     while (TotalValues.size() > 1) {
 81         //从小到大排序
 82         sort(TotalValues.begin(), TotalValues.end(), compareWeight);
 83
 84         //将权重最小的两个点提出
 85         NODE *tmp1 = *TotalValues.begin();
 86         TotalValues.erase(TotalValues.begin());
 87
 88         NODE *tmp2 = *TotalValues.begin();
 89         TotalValues.erase(TotalValues.begin());
 90
 91         //合成新节点再放回去
 92         NODE *CombinedNode = new NODE('#', tmp1->weight + tmp2->weight);
 93         CombinedNode->ptrLeft = tmp1;
 94         CombinedNode->ptrRight = tmp2;
 95         tmp1->ptrParent = tmp2->ptrParent = CombinedNode;
 96
 97         TotalValues.push_back(CombinedNode);
 98     }
 99
100     //记下生成的Huffman Tree的根节点
101     NODE *ptrRoot = *TotalValues.begin();
102
103     if (ptrRoot == nullptr) {
104         cout << "Empty BinaryTree" << endl;
105         return 0;
106     }
107
108     //根据生成的Huffman Tree求各节点的编码
109     //存放所有叶子节点
110     //从叶子往根逆向求相应编码
111     vector<NODE *> leaves;
112     GetLeaf(ptrRoot, leaves);
113
114     sort(leaves.begin(),leaves.end(),compareAlphabet);
115
116     //树的带权路径长度
117     float WPL = 0.0f;
118
119     for (auto leaf:leaves) {
120
121         char alphe = leaf->value;
122         float tmpWPL = leaf->weight;
123
124         string code;
125         while (leaf->ptrParent != nullptr) {
126             //判断是左节点还是右节点
127             if (leaf == leaf->ptrParent->ptrLeft) {
128                 code = '0' + code;
129             } else {
130                 code = '1' + code;
131             }
132             leaf = leaf->ptrParent;
133         }
134         WPL += tmpWPL * code.length();
135         cout << alphe << " : " << code << endl;
136     }
137
138     cout << endl << "WPL : " << WPL << endl;
139     //缺少delete相关功能
140
141     return 0;
142 }

Bad Version

转载于:https://www.cnblogs.com/makejeffer/p/5027477.html

递归求解并生成哈夫曼编码的代码实现相关推荐

  1. 数据结构编程实践(七)创建哈夫曼树、生成哈夫曼编码、完成图片的压缩与解压缩

    一.对图片的压缩与解压缩,涉及以下内容: 1.文件读写 2.创建Huffman树 3.生成Huffman编码 4.压缩图片文件 5 .  解压缩图片文件 二.将项目分成三个小任务,下一任务是在上一任务 ...

  2. 树:哈夫曼树和哈夫曼编码的详细介绍以及代码实现

    闲扯前言 哈夫曼编码的代码实现对于初学数据结构的同学可能会有些困难,没有必要灰心,其实没啥,学习就犹如攀登一座又一座的山峰,每当我们攻克一个难点后,回首来看,也不过如此嘛.我们要做的就是不断的去攀越学 ...

  3. C语言霍夫曼编码压缩,数据结构大作业——哈夫曼编码压缩BMP格式文件

    数据结构大作业--哈夫曼编码压缩BMP格式文件 首先需要了解BMP图像格式 BMP图像格式详解 其次需要了解哈夫曼编码如何对BMP文件进行压缩 哈夫曼压缩与解压缩 编程部分 使用的头文件 虽然这里用了 ...

  4. c语言递归计算哈夫曼编码,哈夫曼树遍历求WPL和哈夫曼编码C语言--For初学者

    这篇文章使用纯c来写的,实现了生成哈夫曼树.求WPL和生成哈夫曼编码的应用,思路是,先定义一个结构体如下 typedef struct node { int weight; struct node * ...

  5. 使用哈夫曼编码进行文件压缩

    给你一个图片文件,要求对其进行无损压缩, 看看压缩效果如何. 思路:读取文件-> 得到赫夫曼编码表 -> 完成压缩 将前面压缩的文件,重新恢复成原来的文件. 思路:读取压缩文件(数据和赫夫 ...

  6. labview霍夫曼编码_香农编码与霍夫曼编码

    一.香农-范诺编码 香农-范诺(Shannon-Fano)编码的目的是产生具有最小冗余的码词(code word).其基本思想是产生编码长度可变的码词.码词长度可变指的是,被编码的一些消息的符号可以用 ...

  7. 二叉树的基本操作及哈夫曼编码/译码系统的实现

    二叉树的基本操作及哈夫曼编码/译码系统的实现 实验目的和要求 掌握二叉树的二叉链表存储表示及遍历操作实现方法. 实现二叉树遍历运算的应用:求二叉树中叶结点个数.结点总数.二叉树的高度,交换二叉树的左右 ...

  8. 贪心算法(Greedy Algorithm)之霍夫曼编码

    文章目录 1. 贪心算法 2. 应用 2.1 找零钱 2.2 区间覆盖 2.3 霍夫曼编码 霍夫曼编码完整代码 1. 贪心算法 我们希望在一定的限制条件下,获得一个最优解 每次都在当前的标准下做出当下 ...

  9. 基于哈夫曼编码完成的文件压缩及解压

    这几天在较为认真的研究基于哈夫曼编码的文件压缩及解压,费了点时间,在这分享一下: 这里用链式结构,非顺序表结构: 文件压缩: 1.获取文件信息(这里采用TXT格式文本): 2.压缩文件: 3.写配置文 ...

最新文章

  1. 取代现有电商和实体店菜市场的新模式
  2. python小数乘法_Polymorph:支持几乎所有现有协议的实时网络数据包操作框架
  3. 赋值运算符 += 面试题小陷阱
  4. 上传文件返回数据提示下载
  5. 总的秒数等于几小时几分钟几秒(Python)
  6. 阿里 Goldeneye 四个环节落地智能监控:预测、检测、报警及定位
  7. STL::map默认会按照.first的字母顺序排列
  8. linux – syslog,rsyslog和syslog-ng之间有什么区别?
  9. 旋转区域_高空旋转雾化机雾桩应用场所、高压喷雾立杆式降尘设备,高压微雾除尘系统原理以及优势...
  10. 配置Visual Studio Code用作51单片机C51代码编辑器,替代KeilC编辑代码事半功倍!
  11. TCP AIMD Algorithm (copy)
  12. Machine Learning 简介与学习路线
  13. 2022-2028全球与中国工业蜂窝网关市场现状及未来发展趋势
  14. R语言使用diag函数生成一个N行N列的单位矩阵
  15. Shell中EOF的用法
  16. 【蓝牙串口无线烧写程序】适用于STM32F405RG的Bootloader
  17. 36个非常有用的电脑知识?
  18. 智信分销拼团拍卖商城v3.38.3
  19. 推荐机制 协同过滤和基于内容推荐的区别
  20. 如何将你原来的服务器迁移到腾讯云服务器?

热门文章

  1. windows2003 mstsc 远端连线,减少可会话数目 ,同一用户只允许一个会话
  2. android 绑定端口号,android 获取IP端口号等地址
  3. 9点到17点半 cron_SpringQuartz定时任务的cron表达式书写
  4. 信号源的ALC环路介绍
  5. 中兴手机数据通道打不开_我用的是中兴手机,里面有流量,但是数据开不了,应该怎么办呢?...
  6. winlogon.exe错误:小心设置搜狗拼音输入法
  7. numpy和scipy安装
  8. 09机器学习实战之多元线性回归
  9. Keras入门(一)搭建深度神经网络(DNN)解决多分类问题
  10. 为什么重启路由器 经常重启让WiFi更快