采用C++实现哈夫曼树的创建并输出哈夫曼编码

一、这篇随笔来自一道信息论的作业题,因为手动编码过于复杂,所以想到了编程解决,原题目如下图所示:

 二、源代码如下:

  1 #include <iostream>
  2 #include <string>
  3 #include <deque>
  4 #include <algorithm>
  5 using namespace std;
  6 struct Node
  7 {
  8     Node *parent, *lchild, *rchild;
  9     pair<float, string> value;
 10 };
 11 class Tree
 12 {
 13 public:
 14     int max;
 15     deque<pair<float, string>> leafs; //存放所有叶子
 16     Node *root;
 17     void hfTree();                                //将所有叶子组合成哈夫曼树
 18     void showLeafs();                             //输出所有叶子节点
 19     Tree(deque<pair<float, string>>);             //构造函数
 20     bool findLeaf(const pair<float, string> &);   //查找叶子
 21     bool deleteLeaf(const pair<float, string> &); //删除叶子
 22     void sortLeafs();
 23 };
 24 //重载pair的加法运算
 25 pair<float, string> operator+(pair<float, string> pr1, pair<float, string> pr2)
 26 {
 27     return pair<float, string>(pr1.first + pr2.first, pr1.second + pr2.second);
 28 }
 29 //Tree的构造函数
 30 Tree::Tree(deque<pair<float, string>> lf)
 31 {
 32     int count = 0;
 33     for (deque<pair<float, string>>::iterator it = lf.begin(); it != lf.end(); it++)
 34     {
 35         this->leafs.push_front(*it);
 36         count++;
 37     }
 38     this->max = count;
 39     this->root = NULL;
 40 }
 41 //输出所有叶子节点
 42 void Tree::showLeafs()
 43 {
 44     cout << "There are " << this->max << " leafs:" << endl;
 45     for (deque<pair<float, string>>::iterator it = this->leafs.begin(); it != this->leafs.end(); it++)
 46     {
 47         cout << "weight:\t" << it->first << "\tcontent:\t" << it->second << endl;
 48     }
 49     cout << "------------------------------------------------------------------------------------" << endl;
 50 }
 51 //根据键值对判断是否存在该叶子
 52 bool Tree::findLeaf(const pair<float, string> &pr)
 53 {
 54     for (deque<pair<float, string>>::iterator it = this->leafs.begin(); it != this->leafs.end(); it++)
 55     {
 56         if ((*it) == pr)
 57         {
 58             return true;
 59         }
 60     }
 61     return false;
 62 }
 63 //根据键值对删除一个叶子
 64 bool Tree::deleteLeaf(const pair<float, string> &pr)
 65 {
 66     for (deque<pair<float, string>>::iterator it = this->leafs.begin(); it != this->leafs.end(); it++)
 67     {
 68         if ((*it) == pr)
 69         {
 70             pair<float, string> temp = this->leafs.back();
 71             while (temp != (*it))
 72             {
 73                 this->leafs.pop_back();
 74                 this->leafs.push_front(temp);
 75                 temp = this->leafs.back();
 76             }
 77             this->leafs.pop_back();
 78             return true;
 79         }
 80     }
 81     return false;
 82 }
 83 //删除deque<Node*>中的一个元素
 84 void deleteNode(deque<Node *> &temp, const pair<float, string> &pr)
 85 {
 86     for (deque<Node *>::iterator it = temp.begin(); it != temp.end(); it++)
 87     {
 88         if ((*it)->value == pr)
 89         {
 90             Node *nd = temp.back();
 91             while (nd->value != pr)
 92             {
 93                 temp.pop_back();
 94                 temp.push_front(nd);
 95                 nd = temp.back();
 96             }
 97             temp.pop_back();
 98             return;
 99         }
100     }
101 }
102 //根据键值对找到节点并返回其地址
103 Node *findNode(deque<Node *> &temp, const pair<float, string> &pr)
104 {
105     for (deque<Node *>::iterator it = temp.begin(); it != temp.end(); it++)
106     {
107         if ((*it)->value == pr)
108         {
109             return *it;
110         }
111     }
112     return NULL;
113 }
114 bool isIn(deque<Node *> &temp, const pair<float, string> &pr)
115 {
116     for (deque<Node *>::iterator it = temp.begin(); it != temp.end(); it++)
117     {
118         if ((*it)->value == pr)
119         {
120             return true;
121         }
122     }
123     return false;
124 }
125 //根据所存的叶子节点构造哈夫曼树
126 void Tree::hfTree()
127 {
128     deque<Node *> temp;
129     temp.push_front(NULL);
130     while (this->leafs.begin() != this->leafs.end())
131     {
132         //对所有叶子排序并取出概率最小的两个叶子节点
133         this->sortLeafs();
134         pair<float, string> pr1;
135         pair<float, string> pr2;
136         if (this->leafs.back() == this->leafs.front()) //表明只剩一个叶子了
137         {
138             pr1 = pr2 = this->leafs.front();
139             this->leafs.pop_front();
140         }
141         else
142         {
143             pr1 = this->leafs.front();
144             this->leafs.pop_front();
145             pr2 = this->leafs.front();
146             this->leafs.pop_front();
147         }
148         //首次合并,特殊处理
149         if (temp.front() == NULL)
150         {
151             temp.pop_front();
152             Node *node = new Node;
153             if (pr1 == pr2)
154             {
155                 node->lchild = node->parent = node->rchild = NULL, node->value = pr1;
156             }
157             else
158             {
159                 Node *node1 = new Node;
160                 Node *node2 = new Node;
161                 node1->value = pr1, node2->value = pr2, node->value = pr1 + pr2;
162                 node1->lchild = node1->rchild = node2->rchild = node2->lchild = node->parent = NULL;
163                 node1->parent = node2->parent = node, node->lchild = node1, node->rchild = node2;
164             }
165             this->leafs.push_front(node->value);
166             temp.push_front(node);
167         }
168         else
169         {
170             Node *node = new Node;
171             if (pr1 == pr2) //只剩一个节点了而且是被处理过的,表明所有节点处理完毕,直接退出
172             {
173                 break;
174             }
175             else
176             {
177                 //新选出的两个节点都是已经处理后得到的根节点
178                 if (isIn(temp, pr1) && isIn(temp, pr2))
179                 {
180                     Node *node1 = findNode(temp, pr1);
181                     Node *node2 = findNode(temp, pr2);
182                     node->value = pr1 + pr2;
183                     node->parent = NULL;
184                     node1->parent = node2->parent = node, node->lchild = node1, node->rchild = node2;
185                     this->deleteLeaf(pr1), this->deleteLeaf(pr2), deleteNode(temp, pr1), deleteNode(temp, pr2); //删除选出来的两个节点
186                     this->leafs.push_front(node->value);
187                 }
188                 else if (isIn(temp, pr1))
189                 {
190                     Node *tp = findNode(temp, pr1);
191                     Node *node2 = new Node;
192                     node2->value = pr2, node->value = pr1 + pr2;
193                     node2->rchild = node2->lchild = node->parent = NULL;
194                     node2->parent = tp->parent = node, node->rchild = node2, node->lchild = tp;
195                     this->deleteLeaf(pr1), this->deleteLeaf(pr2);               //删除选出来的节点
196                     this->leafs.push_front(node->value), deleteNode(temp, pr1); //将合并的节点放到生成树和原始集合中
197                 }
198                 else if (isIn(temp, pr2))
199                 {
200                     Node *tp = findNode(temp, pr2);
201                     Node *node1 = new Node;
202                     node1->value = pr1, node->value = pr1 + pr2;
203                     node1->rchild = node1->lchild = node->parent = NULL;
204                     node1->parent = tp->parent = node, node->lchild = node1, node->rchild = tp;
205                     this->deleteLeaf(pr1), this->deleteLeaf(pr2);               //删除选出来的节点
206                     this->leafs.push_front(node->value), deleteNode(temp, pr2); //将合并的节点放到生成树和原始集合中
207                 }
208                 else
209                 {
210                     Node *node1 = new Node;
211                     Node *node2 = new Node;
212                     node->value = pr1 + pr2;
213                     node->parent = NULL;
214                     node1->value = pr1, node2->value = pr2;
215                     node1->parent = node2->parent = node, node->lchild = node1, node->rchild = node2;
216                     node1->lchild = node2->lchild = node1->rchild = node2->rchild = node->parent = NULL;
217                     this->deleteLeaf(pr1), this->deleteLeaf(pr2); //删除选出来的两个节点
218                     this->leafs.push_front(node->value);
219                 }
220             }
221             temp.push_front(node);
222         }
223     }
224     this->root = temp.front();
225 }
226 
227 //前序遍历一棵树
228 void prelook(Node *root,string str)
229 {
230     
231     if (root != NULL)
232     {
233         if (root->lchild == NULL && root->rchild == NULL)
234         {
235             cout << "weight:\t" << root->value.first << "\tcontent:\t" << root->value.second << "\tcode:\t"<<str<<endl;
236         }
237         if (root->lchild != NULL)
238         {
239             str+="0";
240             prelook(root->lchild,str);
241             str.pop_back();
242         }
243         if (root->rchild != NULL)
244         {
245             str+="1";
246             prelook(root->rchild,str);
247             str.pop_back();
248         }
249     }
250 }
251 //重载操作符,实现两个集合的笛卡儿积
252 Tree operator+(Tree tr1, Tree tr2)
253 {
254     deque<pair<float, string>> temp;
255     for (deque<pair<float, string>>::iterator it1 = tr1.leafs.begin(); it1 != tr1.leafs.end(); it1++)
256     {
257         for (deque<pair<float, string>>::iterator it2 = tr2.leafs.begin(); it2 != tr2.leafs.end(); it2++)
258         {
259             temp.push_back(pair<float, string>((*it1).first * (*it2).first, (*it1).second + (*it2).second));
260         }
261     }
262     return Tree(temp);
263 }
264 //对一棵树的叶子节点进行排序
265 void Tree::sortLeafs()
266 {
267     sort(this->leafs.begin(), this->leafs.end());
268 }
269 
270 int main()
271 {
272     deque<pair<float, string>> temp;
273     temp.push_front(pair<float, string>(0.5, "a1"));
274     temp.push_front(pair<float, string>(0.3, "a2"));
275     temp.push_front(pair<float, string>(0.2, "a3"));
276     Tree tr = Tree(temp)+Tree(temp)+Tree(temp);
277     tr.hfTree();
278     prelook(tr.root,"");
279     system("pause");
280     return 0;
281 }

三、修改源代码第276行可以实现对任意次方笛卡尔积结果的编码,第三问输出结果如下:

猜你喜欢

转载自www.cnblogs.com/mitoohi/p/12535866.html