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

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