采用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