Java学习者论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

手机号码,快捷登录

恭喜Java学习者论坛(https://www.javaxxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,购买链接:点击进入购买VIP会员
JAVA高级面试进阶视频教程Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程

Go语言视频零基础入门到精通

Java架构师3期(课件+源码)

Java开发全终端实战租房项目视频教程

SpringBoot2.X入门到高级使用教程

大数据培训第六期全套视频教程

深度学习(CNN RNN GAN)算法原理

Java亿级流量电商系统视频教程

互联网架构师视频教程

年薪50万Spark2.0从入门到精通

年薪50万!人工智能学习路线教程

年薪50万!大数据从入门到精通学习路线年薪50万!机器学习入门到精通视频教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程 MySQL入门到精通教程
查看: 193|回复: 0

[默认分类] C/C++ — 哈夫曼树与哈夫曼编码的实现

[复制链接]
  • TA的每日心情
    开心
    2021-12-13 21:45
  • 签到天数: 15 天

    [LV.4]偶尔看看III

    发表于 2018-3-18 17:05:32 | 显示全部楼层 |阅读模式
      哈夫曼树是一种特殊的树,结合前面做书上动态规划题的了解,哈夫曼树就是最优二叉树。
      建立一颗哈夫曼树前需要明确条件,比如一颗词典树(节点值为单词),我们希望能通过我们的查找习惯建立一颗更快、更合适的二叉树,那么,这里的条件就是树中每个单词的搜索频率,显然,搜索频率越高的单词越靠近树根,查找效率会更好,通过搜索频率(权值)与节点离根节点的路径距离计算出WPL(带权路径长),当词典树的形态为某种情况的时候(哈夫曼树总是一颗满二叉树 — 除叶节点外,内部节点都是儿孙满堂的),WPL最小,那么这样的一颗二叉树就是最优二叉树,也就是我们想要的树的形态了。
      可通过动态规划算法证明,上面描述的二叉树的各个节点是否与最优二叉树的各节点相等。当然书上还有更严谨的算法数学证明。
      WPL计算很简单,公式:WPL = ∑ L[sub]i[/sub] × P[sub]i[/sub] (其中L是路径长度,P是权值)。
      建立哈夫曼树很简单:初始化节点数据,维护一个最小优先队列,将节点按权值大小加入到优先队列中,然后将队列中的节点弹出,由下而上建立哈夫曼树。
      算法伪python代码:

    1. """
    2. class node:
    3.     int f; //权值
    4.     type var; //其他数据类型
    5.     node left;
    6.     ndoe right;
    7. """
    8. def build_Huffman_tree(nodes):
    9.     """
    10.     nodes是一组node类型的节点
    11.     """
    12.     priority_queue<node> que = nodes; //加入到优先队列
    13.     while que.size > 1:
    14.         left = que.top;
    15.         right = que.top;
    16.         p = new node; // 请求一个新节点
    17.         p.f = left.f + right.f;
    18.         que.add = p;
    19.     return que.top;
    复制代码

      哈夫曼编码是一种变长编码的方式,变长编码一般比定长编码压缩率高,所以这里不考虑定长编码,但定长编码也很简单,自己制定一个编码表,通过查表的方式编码,效率高。解码也是查表即可。
      制定哈夫曼编码规则:左路径编码为0,右路径编码为1。这样就可以通过遍历二叉树进行编码了。如图:
                   图片来自百度图片
    &nbsp;  解码也很简单,只需要根据制定的规则,再进行树的遍历,然后通过查表即可解码。
      完整代码:

    1. #include <iostream>
    2. #include <string.h>
    3. #define MAXSIZE 0xffff
    4. #define QUE_LEFT(i) (2*(i) + 1)
    5. class node {
    6. public:
    7.         char var;
    8.         size_t freq;
    9.         node * left;
    10.         node * right;
    11.         node() {}
    12.         node(char c, size_t f) : var(c), freq(f) {}
    13.         node(node * l, node * r) : var(0), freq(l->freq + r->freq), left(l), right(r) {}
    14.         virtual ~node() {}
    15. };
    16. class queue : public node{
    17. public:
    18.     size_t size_s;
    19.     node * priority_queue[MAXSIZE];
    20.     queue() : size_s(0) {}
    21.     ~queue() {
    22.         while(!empty())
    23.             size_s--;
    24.     }
    25.     bool empty() const {
    26.         if (size_s == 0)
    27.             return true;
    28.         return false;
    29.     }
    30.     bool full() const {
    31.         if (size_s == MAXSIZE)
    32.             return true;
    33.         return false;
    34.     }
    35.     size_t size() const {
    36.         return size_s;
    37.     }
    38.     void insert(node * n);
    39.     node * pop();
    40. };
    41. void queue::insert(node * n) {
    42.     if (full())
    43.         exit(1);
    44.         int i = size_s++;
    45.         for (; i > 0 && priority_queue[i / 2]->freq >= n->freq; i /= 2)
    46.                 priority_queue[i] = priority_queue[i / 2];
    47.         priority_queue[i] = n;
    48. }
    49. node * queue::pop() {
    50.         if (empty())
    51.                 exit(1);
    52.         size_s--;
    53.         node * root = priority_queue[0];
    54.         int i = 0;
    55.         for (int l; QUE_LEFT(i) < (int)size_s; i = l) {
    56.             l = QUE_LEFT(i);
    57.                 if (l + 1 < (int)size_s && priority_queue[l + 1]->freq < priority_queue[l]->freq)
    58.                         l++;
    59.         priority_queue[i] = priority_queue[l];
    60.         }
    61.         priority_queue[i] = priority_queue[size_s];
    62.         return root;
    63. }
    64. class HuffmanTree {
    65. public:
    66.         node * build_Huffman_tree(std::string str, int * & freq);
    67.         void coding(node * root, char * write, char ** code, int len);
    68.         std::string encode(node * root, std::string str, char ** code);
    69.         void decode(node * root, std::string codes);
    70.         void destory(node * root);
    71. };
    72. node * HuffmanTree::build_Huffman_tree(std::string str, int * & freq) {
    73.     queue que;
    74.         for (auto v : str)
    75.                 ++freq[(int)v];
    76.         for (int i = 0; i < 128 + 1; i++)
    77.                 if (freq[i]) {
    78.                         node * n = new node(i, freq[i]);
    79.                         que.insert(n);
    80.                 }
    81.         while (que.size() > 1) {
    82.                 node * left = que.pop();
    83.                 node * right = que.pop();
    84.                 node * parent = new node(left, right);
    85.                 que.insert(parent);
    86.         }
    87.         return que.pop();
    88. }
    89. void HuffmanTree::coding(node * pr, char * write, char ** code, int len) {
    90.     static char buf[MAXSIZE >> 1], *out = buf;
    91.         if (pr->var) {
    92.         write[len] = 0;
    93.                 strcpy(out, write);
    94.                 code[(int)pr->var] = out;
    95.                 out += len + 1;
    96.                 return;
    97.         }
    98.         write[len] = "0"; coding(pr->left, write, code, len + 1);
    99.         write[len] = "1"; coding(pr->right, write, code, len + 1);
    100. }
    101. std::string HuffmanTree::encode(node * root, std::string str, char ** code) {
    102.     char * write = new char;
    103.         coding(root, write, code, 0);
    104.         delete write;
    105.         std::string read = "";
    106.         for (auto v : str)
    107.                 read += code[(int)v];
    108.         return read;
    109. }
    110. void HuffmanTree::decode(node * root, std::string codes) {
    111.         node * n = root;
    112.         int i = 0;
    113.         while (codes[i]) {
    114.                 if (codes[i++] == "0")
    115.                         n = n->left;
    116.                 else
    117.                         n = n->right;
    118.                 if (n->var) putchar(n->var), n = root;
    119.         }
    120. }
    121. void HuffmanTree::destory(node * root) {
    122.     if (root) {
    123.         destory(root->left);
    124.         destory(root->right);
    125.         delete root;
    126.     }
    127. }
    128. void TravelTree(node * root) {
    129.     if (root) {
    130.         std::cout << root->freq;
    131.         if (root->var)
    132.             std::cout << ":" << root->var;
    133.         std::cout << std::endl;
    134.         TravelTree(root->left);
    135.         TravelTree(root->right);
    136.     }
    137. }
    138. int main()
    139. {
    140.     int freq[128 + 1] = { 0 }, *f = freq;
    141.     char *code[MAXSIZE + 1];
    142.     node * root;
    143.         HuffmanTree tree;
    144.         std::string str = "hello world!";
    145.         root = tree.build_Huffman_tree(str, f);
    146.         str = tree.encode(root, str, code);
    147.         for (int i = 0; i < 128 + 1; i++)
    148.         if (code[i]) {
    149.             std::cout << (char)i << ":" << freq[i] <<
    150.             " --- " << code[i] << std::endl;
    151.         }
    152.         std::cout << "编码结果:" << str << std::endl;
    153.         std::cout << "解码:";
    154.         tree.decode(root, str);
    155.     return 0;
    156. }
    复制代码

      运行结果:

    &nbsp;  参考资料:
        1.这个网址是在维基百科找到的,有各种语言的哈夫曼编码的实现:http://rosettacode.org/wiki/Huffman_coding
        2.http://www.cnblogs.com/sench/p/7798064.html
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|Java学习者论坛 ( 声明:本站资料整理自互联网,用于Java学习者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2024-5-17 04:08 , Processed in 0.362530 second(s), 46 queries .

    Powered by Discuz! X3.4

    © 2001-2017 Comsenz Inc.

    快速回复 返回顶部 返回列表