采用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行可以实现对任意次方笛卡尔积结果的编码,第三问输出结果如下:

 

 

 

 //表明只剩一个叶子了


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM