经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » C++ » 查看文章
哈夫曼树(Huffman树)原理分析及实现
来源:cnblogs  作者:一叶飘落尽知秋  时间:2022/1/17 11:12:46  对本文有异议

哈夫曼树(Huffman树)原理分析及实现

1 构造原理

假设有n个权值,则构造出的哈夫曼树有n个叶子结点。 n个权值分别设为 w1、w2、…、wn,则哈夫曼树的构造规则为:
  (1) 将w1、w2、…,wn看成是有n 棵树的森林(每棵树仅有一个结点);
  (2) 在森林中选出两个根结点的权值最小的树合并,作为一棵新树的左、右子树,且新树的根结点权值为其左、右子树根结点权值之和;
  (3)从森林中删除选取的两棵树,并将新树加入森林;
  (4)重复(2)、(3)步,直到森林中只剩一棵树为止,该树即为所求得的哈夫曼树。

  1. 显然对n个权值,构造哈夫曼树树需要合并n-1次,形成的树结点总数为2n-1

例如:A:60, B:45, C:13 D:69 E:14 F:5 G:3

第一步:找出字符中最小的两个,小的在左边,大的在右边,组成二叉树。

F和G最小,因此如图,从字符串频率计数中删除F与G,并返回G与F的和 8给频率表

image-20220105081831621

重复第一步:

image-20220105081848649

image-20220105081907259

image-20220105081926271

image-20220105081940474

image-20220105081958021

编码规则:添加 0 和 1,规则左0 右1

image-20220105082019527

2 代码实现

根据哈夫曼树的构造原理,为方便实现,我们使用数组来存储每个结点,其命名为Tree;

2.1 节点结构

节点具有以下结构:

  1. //结点结构
  2. struct Node {
  3. int val{0}; //节点的值
  4. Node* left{nullptr}; //节点的左孩子
  5. Node* right{nullptr}; //节点的右孩子
  6. Node* parent{nullptr}; //节点的父节点
  7. explicit Node(int value) : val(value) {}
  8. Node(int value, Node* pleft, Node* pRight, Node* pParent)
  9. : val(value), left(pleft), right(pRight), parent(pParent) {}
  10. };

2.2 类的实现

Huffman.h

  1. #include <iostream>
  2. #include <queue>
  3. #include <string>
  4. #include <vector>
  5. using namespace std;
  6. struct Node {
  7. int val{0}; //节点的值
  8. Node* left{nullptr}; //节点的左孩子
  9. Node* right{nullptr}; //节点的右孩子
  10. Node* parent{nullptr}; //节点的父节点
  11. explicit Node(int value) : val(value) {}
  12. Node(int value, Node* pleft, Node* pRight, Node* pParent)
  13. : val(value), left(pleft), right(pRight), parent(pParent) {}
  14. };
  15. class Compare //比较类,用于构造Node*类型的priority_queue
  16. {
  17. public:
  18. bool operator()(Node* a, Node* b) {
  19. return a->val > b->val; //结点的值越小越靠前
  20. }
  21. };
  22. class HuffmanTree {
  23. public:
  24. HuffmanTree();
  25. ~HuffmanTree();
  26. Node* Create();
  27. void PreOrder(Node* pNode);
  28. void InOrder(Node* pNode);
  29. void PostOrder(Node* pNode);
  30. void Encode(Node* pNode, string code);
  31. private:
  32. Node* root; // 哈夫曼树头
  33. priority_queue<Node*, vector<Node*>, Compare> nodes;
  34. void destroyTree(Node* pNode);
  35. };

Hufman.cpp

  1. #include "Huffman.h"
  2. HuffmanTree::HuffmanTree() {
  3. // priority_queue没有clear
  4. while (!nodes.empty()) nodes.pop();
  5. int a[] = {4, 3, 5, 8, 7, 9};
  6. int len = sizeof(a) / sizeof(a[0]);
  7. for (int i = 0; i < len; i++) { nodes.push(new Node(a[i])); }
  8. root = nullptr;
  9. }
  10. HuffmanTree::~HuffmanTree() {
  11. destroyTree(root);
  12. }
  13. void HuffmanTree::destroyTree(Node* pNode) {
  14. if (pNode == nullptr)
  15. return;
  16. destroyTree(pNode->left);
  17. destroyTree(pNode->right);
  18. delete pNode;
  19. }
  20. Node* HuffmanTree::Create() {
  21. while (nodes.size() > 1) {
  22. Node* p1 = nodes.top();
  23. nodes.pop();
  24. Node* p2 = nodes.top();
  25. nodes.pop();
  26. Node* cur = new Node(p1->val + p2->val);
  27. cur->left = p1;
  28. cur->right = p2;
  29. p1->parent = cur;
  30. p2->parent = cur;
  31. nodes.push(cur);
  32. }
  33. root = nodes.top();
  34. nodes.pop();
  35. return root;
  36. }
  37. void HuffmanTree::PreOrder(Node* pNode) {
  38. if (pNode == nullptr)
  39. return;
  40. cout << pNode->val << " ";
  41. PreOrder(pNode->left);
  42. PreOrder(pNode->right);
  43. }
  44. void HuffmanTree::InOrder(Node* pNode) {
  45. if (pNode == nullptr)
  46. return;
  47. InOrder(pNode->left);
  48. cout << pNode->val << " ";
  49. InOrder(pNode->right);
  50. }
  51. void HuffmanTree::PostOrder(Node* pNode) {
  52. if (pNode == nullptr)
  53. return;
  54. PostOrder(pNode->left);
  55. PostOrder(pNode->right);
  56. cout << pNode->val << " ";
  57. }
  58. void HuffmanTree::Encode(Node* pNode, string code) {
  59. //叶子节点的处理
  60. if (pNode->left == nullptr && pNode->right == nullptr)
  61. cout << pNode->val << " 被编码为 " << code << endl;
  62. if (pNode->left) {
  63. //左子树,编码code添加'0'
  64. code += "0";
  65. Encode(pNode->left, code);
  66. //编码code删除'0'
  67. code.erase(code.end() - 1);
  68. }
  69. if (pNode->right) {
  70. //左子树,编码code添加'1'
  71. code += "1";
  72. Encode(pNode->right, code);
  73. //编码code删除'1'
  74. code.erase(code.end() - 1);
  75. }
  76. }

3 测试代码及输出

  1. int main() {
  2. HuffmanTree obj;
  3. Node* root = obj.Create();
  4. cout << "先序遍历: ";
  5. obj.PreOrder(root);
  6. cout << endl;
  7. cout << "中序遍历: ";
  8. obj.InOrder(root);
  9. cout << endl;
  10. cout << "后序遍历: ";
  11. obj.PostOrder(root);
  12. cout << endl;
  13. cout << "哈夫曼编码: ";
  14. obj.Encode(root, "");
  15. return 0;
  16. }

正确输出:
image-20220105003326817

4 参考资料

1.哈夫曼树算法及C++实现
2.百度百科·哈夫曼树
3.数据结构:Huffman树(哈夫曼树)原理及C++实现

原文链接:http://www.cnblogs.com/paul-617/p/15765291.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号