中国大学MOOC-数据结构基础习题集、04-3、Huffman Codes
题目链接:http://www.patest.cn/contests/mooc-ds/04-3
题目分析:这是一道考察“哈夫曼编码”的问题,但是这里大家不要陷入一个误区:就是一定要把哈夫曼树构造出来。我们首先分析一下题目的需求:
输入:第一行是结点数目num;第二行是每个结点数据data及出现的次数weight;第三行是测试数据的组数checkNum;第四行及以后是结点数据ch及编码s。
输出:对于每一组测试数据,输出编码是否符合“哈夫曼编码”,是则输出Yes,否则输出No。
符合“哈夫曼编码”需要符合两个条件:①WPL最小,②编码的前缀不能是其他编码的前缀。
特别说明:
1) 这里我们不用“堆”,改用C++标准库中的优先级队列。使用优先级队列需要引入头文件 #include <queue>。优先级队列的特点是,当我们把数据放入队列里,编译器会自动按照“优先级”帮我们排好顺序。
// 使用优先级队列模拟“堆” priority_queue<int, vector<int>, greater<int> >pq; // 向队列中添加元素 pq.push(f[i]);
2) 计算WPL的值,从队列中取出两个元素,相加之后再放回队列里。如果对这段代码不理解,不妨自己拿出纸笔走一遍代码。
1 // 计算WPL的值 2 int myWpl = 0; 3 while(!pq.empty()) 4 { 5 int myTop = pq.top(); 6 pq.pop(); 7 if(!pq.empty()) 8 { 9 int myTop2 = pq.top(); 10 pq.pop(); 11 pq.push(myTop + myTop2); 12 int m = myTop + myTop2; 13 myWpl += m; 14 } 15 }
3) 标准库并没有为map制定sort函数,因此我们用vector装载pair类型,既可以模仿出map的功能,又可以用vector的排序函数了。
// 要使用排序函数sort,必须引入此头文件 #include <algorithm> // 用PAIR来代替pair<char, string> typedef pair<char, string> PAIR; // cmp函数决定是从小到大排,还是从大到小排 // 还有按什么内容排,这里是按编码的长度排序 int cmp(const PAIR& x, const PAIR& y) { return x.second.size() < y.second.size(); } // vector的定义 vector<PAIR> checkVec; // 向vector中添加元素 checkVec.push_back(make_pair(ch, s)); // 按照编码的长度排序 sort(checkVec.begin(), checkVec.end(), cmp);
4) 判断前缀问题,我们用到了substr函数,取字符串中的一段并与当前编码进行比较。
1 for(int i=0; i<num; i++) 2 { 3 string tmp = checkVec[i].second; 4 for(int j=i+1; j<num; j++) 5 { 6 if(checkVec[j].second.substr(0,tmp.size())==tmp) 7 flag = false; 8 } 9 }
代码分析:
头文件及其他相关声明:1~11
比较函数,用于sort中用来指定依据什么来进行排序,以及从小到大还是从大到小:14~18
输入:19~35
计算WPL值:36~50
输入测试数据及进行处理、判断:51~98
1 #include <iostream> 2 // 要使用排序函数sort,必须引入此头文件 3 #include <algorithm> 4 #include <map> 5 #include <queue> 6 7 using namespace std; 8 9 // 用PAIR来代替pair<char, string> 10 typedef pair<char, string> PAIR; 11 12 // cmp函数决定是从小到大排,还是从大到小排 13 // 还有按什么内容排,这里是按编码的长度排序 14 int cmp(const PAIR& x, const PAIR& y) 15 { 16 return x.second.size() < y.second.size(); 17 } 18 19 int main() 20 { 21 int num; 22 cin >> num; 23 char *c = new char[num]; 24 int *f = new int[num]; 25 map<char, int> myMap; 26 // 使用优先级队列模拟“堆” 27 priority_queue<int, vector<int>, greater<int> >pq; 28 // 输入结点及出现次数 29 for(int i=0; i<num; i++) 30 { 31 cin >> c[i] >> f[i]; 32 myMap[c[i]] = f[i]; 33 // 向队列中添加元素 34 pq.push(f[i]); 35 } 36 // 计算WPL的值 37 int myWpl = 0; 38 while(!pq.empty()) 39 { 40 int myTop = pq.top(); 41 pq.pop(); 42 if(!pq.empty()) 43 { 44 int myTop2 = pq.top(); 45 pq.pop(); 46 pq.push(myTop + myTop2); 47 int m = myTop + myTop2; 48 myWpl += m; 49 } 50 } 51 // 输入测试数据 52 int checkNum; 53 cin >> checkNum; 54 for(int i=0; i<checkNum; i++) 55 { 56 int wpl = 0; 57 char ch; 58 string s; 59 // vector的定义 60 vector<PAIR> checkVec; 61 for(int j=0; j<num; j++) 62 { 63 cin >> ch >> s; 64 // 向vector中添加元素 65 checkVec.push_back(make_pair(ch, s)); 66 wpl += s.size() * myMap[ch]; 67 } 68 // 按照编码的长度排序 69 sort(checkVec.begin(), checkVec.end(), cmp); 70 if(wpl != myWpl) 71 { 72 cout << "No" << endl; 73 continue; 74 } 75 else 76 { 77 bool flag = true; 78 79 for(int i=0; i<num; i++) 80 { 81 string tmp = checkVec[i].second; 82 for(int j=i+1; j<num; j++) 83 { 84 if(checkVec[j].second.substr(0,tmp.size())==tmp) 85 flag = false; 86 } 87 } 88 89 if(flag == true) 90 cout << "Yes" << endl; 91 else 92 cout << "No" << endl; 93 continue; 94 } 95 cout << "Yes" << endl; 96 } 97 return 0; 98 }
AC成果: