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

一、问题源自一道信息论的作业题:

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

 二、完整代码如下  1 #include <iostream>

  2 #include <string>
  3 #include <deque>
  4 #include <algorithm>
  5 using namespace std;
  6 struct Node{
  8     Node *parent, *lchild, *rchild;
  9     pair<float, string> value;
 10 };
 11 class Tree{
 13 public:
 14     int max;
 15     deque<pair<float, string>> leafs; //存放所有叶子
 16     Node *root;
 17     void hfTree();                                //将所有叶子组合成哈夫曼树
 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){
 27     return pair<float, string>(pr1.first + pr2.first, pr1.second + pr2.second);
 28 }
 29 //Tree的构造函数
 30 Tree::Tree(deque<pair<float, string>> lf){
 32     int count = 0;
 33     for (deque<pair<float, string>>::iterator it = lf.begin(); it != lf.end(); it++){
 35         this->leafs.push_front(*it);
 36         count++;
 37     }
 38     this->max = count;
 39     this->root = NULL;
 40 } 51 //根据键值对判断是否存在该叶子
 52 bool Tree::findLeaf(const pair<float, string> &pr){
 54     for (deque<pair<float, string>>::iterator it = this->leafs.begin(); it != this->leafs.end(); it++){
 56         if ((*it) == pr){
 58             return true;
 59         }
 60     }
 61     return false;
 62 }
 63 //根据键值对删除一个叶子
 64 bool Tree::deleteLeaf(const pair<float, string> &pr){
 66     for (deque<pair<float, string>>::iterator it = this->leafs.begin(); it != this->leafs.end(); it++){
 68         if ((*it) == pr){
 70             pair<float, string> temp = this->leafs.back();
 71             while (temp != (*it)){
 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){
 86     for (deque<Node *>::iterator it = temp.begin(); it != temp.end(); it++){
 88         if ((*it)->value == pr){
 90             Node *nd = temp.back();
 91             while (nd->value != pr){
 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){
105     for (deque<Node *>::iterator it = temp.begin(); it != temp.end(); it++){
107         if ((*it)->value == pr){
109             return *it;
110         }
111     }
112     return NULL;
113 }
114 bool isIn(deque<Node *> &temp, const pair<float, string> &pr){
116     for (deque<Node *>::iterator it = temp.begin(); it != temp.end(); it++){
118         if ((*it)->value == pr){
120             return true;
121         }
122     }
123     return false;
124 }
125 //根据所存的叶子节点构造哈夫曼树
126 void Tree::hfTree(){
128     deque<Node *> temp;
129     temp.push_front(NULL);
130     while (this->leafs.begin() != this->leafs.end()){
132         //对所有叶子排序并取出概率最小的两个叶子节点
133         this->sortLeafs();
134         pair<float, string> pr1;
135         pair<float, string> pr2;
136         if (this->leafs.back() == this->leafs.front()){//只剩一个叶子了
138             pr1 = pr2 = this->leafs.front();
139             this->leafs.pop_front();
140         }else{
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){
151             temp.pop_front();
152             Node *node = new Node;
153             if (pr1 == pr2){
155                 node->lchild = node->parent = node->rchild = NULL, node->value = pr1;
156             }else{
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         }else{
170             Node *node = new Node;
171             if (pr1 == pr2){//只剩一个节点了而且是被处理过的,表明所有节点处理完毕,直接退出
173                 break;
174             }else{//新选出的两个节点都是已经处理后得到的根节点
178                 if (isIn(temp, pr1) && isIn(temp, pr2)){
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                 }else if (isIn(temp, pr1)){
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                 }else if (isIn(temp, pr2)){
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                 }else{
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){
231     if (root != NULL){
233         if (root->lchild == NULL && root->rchild == NULL){
235             cout << "weight:t" << root->value.first << "tcontent:t" << root->value.second << "tcode:t"<<str<<endl;
236         }
237         if (root->lchild != NULL){
239             str+="0";
240             prelook(root->lchild,str);
241             str.pop_back();
242         }
243         if (root->rchild != NULL){
245             str+="1";
246             prelook(root->rchild,str);
247             str.pop_back();
248         }
249     }
250 }
251 //重载操作符,实现两个集合的笛卡儿积
252 Tree operator+(Tree tr1, Tree tr2){
254     deque<pair<float, string>> temp;
255     for (deque<pair<float, string>>::iterator it1 = tr1.leafs.begin(); it1 != tr1.leafs.end(); it1++){
257         for (deque<pair<float, string>>::iterator it2 = tr2.leafs.begin(); it2 != tr2.leafs.end(); it2++){
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(){
267     sort(this->leafs.begin(), this->leafs.end());
268 }
270 int main(){
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行可以实现对任意次方笛卡尔积结果的编码,第三问输出结果如下:

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

 

 

 

 //表明只剩一个叶子了

原文链接: https://www.cnblogs.com/mitoohi/p/12535866.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍;

也有高质量的技术群,里面有嵌入式、搜广推等BAT大佬

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

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/336482

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年3月1日 下午10:40
下一篇 2023年3月1日 下午10:40

相关推荐