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