一、问题源自一道信息论的作业题:
二、完整代码如下 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行可以实现对任意次方笛卡尔积结果的编码,第三问输出结果如下:
//表明只剩一个叶子了