题目描述:
寂寞的PJ终于找到了一个超级可爱的女朋友,他想给她写一封情书,但是他文笔不好,情商又低,只能写写代码才能维持的了生活这个样子 正好PJ可爱的女朋友也是学计算机的,她刚刚学完《计算机导论》,于是PJ灵机一动,打算用二进制写一封情书给她。 因为PJ凑不出来字数,于是PJ想到了这么一种编码方式来延长自己的情书长度: 1、先用英语写好情书,记录出现的英文字符的种类n( 0 < n < = 52),区分大小写。 2、记录每种英文字符出现的频数,按从大到小的次序排好放入队列。如果频数相同,则按字典序。 3、将当前队列中的队首两元素分别作为左右子节点(频数较高的作为左子节点)创建一个父节点,父节点自身的频数值为左右节点的和。并将该父节点放回到队首。 4、重复上述行为直到队列中所有的元素都已经添加到同一棵二叉树上。 5、从根节点开始以深度优先的方式遍历节点,每个节点的左树枝边值记为0,右树枝边值记为1,直到叶节点,按顺序读取树枝的值便是我们所要的该字符的编码,我们称之为PJ编码。 值得注意的是,PJ希望他的情书可读性更强,所以他只转换英文字符,其他字符都不变。并且在输出情书正文之前他要先给他可爱的女孩一个字典以便读懂这篇情书。 情书的长度不超过600字符
输入:
以文件结尾为结束,输入一整篇英文情书,包括空格和回车。
输出:
前n行以从出现频数高到低输出已经出现的英文字符和它对应的PJ编码,以英文冒号和空格隔开。 接下来按原来的格式输出已经转换成PJ编码形式的情书。
输入
I AM PJ
I Love you so much!
CC
输出
o: 000000000000000
C: 000000000000001
I: 00000000000001
u: 0000000000001
A: 000000000001
J: 00000000001
L: 0000000001
M: 000000001
P: 00000001
c: 0000001
e: 000001
h: 00001
m: 0001
s: 001
v: 01
y: 1
00000000000001 000000000001000000001 0000000100000000001
00000000000001 000000000100000000000000001000001 10000000000000000000000000001 001000000000000000 00010000000000001000000100001!
000000000000001000000000000001
就是哈夫曼编码,碰巧数据结构今天讲了,就写了下。
代码写的有点丑,请见谅。
详细解释看代码
#include<bits/stdc++.h>
using namespace std ;
const int MAXN = 600+11;
const int inf = 0x3f3f3f3f;struct Node{int num,lson,rson; // 字符频率 ,当前节点的左孩子的位置,右孩子的位置。char ch; // 节点的字符int id; // 在顺序表中的位置
}node[MAXN*10]; int sz;// node[] 中存的就是树中的所有节点
bool operator <(Node a,Node b){if(a.num!=b.num)return a.num<b.num;return a.ch>b.ch;
}map<char,int>cnt; // 记录字符 频率
map<char,int>::iterator it;
map<char,string>Hash; // 记录字符对应的编码priority_queue<Node>Q; // 优先队列来维护序列的前2最大值 ,其实本题目不用优先队列也可以的,最大+次大 一定是最大。
void Creat(){int pos1,pos2; // 左孩子的位置,右孩子的位置。while(1){pos1=Q.top().id; Q.pop(); if(Q.empty()) break; // 最后肯定会剩下一个节点。pos2=Q.top().id; Q.pop();Node e;e.num=node[pos1].num+node[pos2].num;e.lson=pos1; e.rson=pos2;e.id=sz; e.ch='a'; // 这里给父节点的字符 赋值什么都可以不影响 // 创建新父节点node[sz++]=e; Q.push(node[sz-1]); //插入父节点}
}
void DFS(string s,int now){ // 遍历哈夫曼树得到字符编码if(node[now].lson==-1){ // 说明到了子叶节点Hash[node[now].ch]=s;cout<<node[now].ch<<": "<<s<<endl;return ;}DFS(s+"0",node[now].lson);DFS(s+"1",node[now].rson);
}string str[MAXN];int id; // 记录输入的文档
void Output(){for(int i=0;i<id;i++){for(int j=0;str[i][j];j++){if(str[i][j]>='a'&&str[i][j]<='z'||str[i][j]>='A'&&str[i][j]<='Z') cout<<Hash[str[i][j]];else cout<<str[i][j];}cout<<endl;}
}
int main(){while(getline(cin,str[id])){for(int i=0;str[id][i];i++) {if(str[id][i]>='a'&&str[id][i]<='z'||str[id][i]>='A'&&str[id][i]<='Z')cnt[str[id][i]]++;}id++;}for(it=cnt.begin();it!=cnt.end();it++){ // 得到子叶节点信息;Node e;e.num=it->second; e.lson=-1; e.rson=-1;e.ch=it->first; e.id=sz;node[sz++]=e; Q.push(node[sz-1]);}Creat(); // 创建哈夫曼树DFS("",sz-1); // 遍历哈夫曼树得到字符编码Output(); //输出编码后文章
return 0;
}