zoukankan      html  css  js  c++  java
  • 递归求解并生成哈夫曼编码的代码实现

    一开始我用的三叉链表来生成哈夫曼编码,这一点都不递归。后来我想起了一度被递归统治地恐惧,我发现哈夫曼树不仅编码可以简单的用递归来求,树的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
  • 相关阅读:
    pycharm 操作excel
    pycharm 增删改查 mysql数据库
    fillder 抓包工具详解
    acunetix 12.0.190902105 破解方法
    Navicat15 最新版本破解版操作步骤
    网站性能优化检测工具
    linux 服务器资源 监控工具
    win10系统git的安装与使用命令
    测试入门基础知识
    Pycharm2020.2 专业版永久激活 免费下载激活插件与参数
  • 原文地址:https://www.cnblogs.com/makejeffer/p/5027477.html
Copyright © 2011-2022 走看看