描述
输入一串字符串,根据给定的字符串中字符出现的频率建立相应哈夫曼树,构造哈夫曼编码表,在此基础上可以对待压缩文件进行压缩(即编码),同时可以对压缩后的二进制编码文件进行解压(即译码)。
输入
多组数据,每组数据一行,为一个字符串(只考虑26个小写字母即可)。当输入字符串为“0”时,输入结束。
输出
每组数据输出2n+3行(n为输入串中字符类别的个数)。第一行为统计出来的字符出现频率(只输出存在的字符,格式为:字符:频度),每两组字符之间用一个空格分隔,字符按照ASCII码从小到大的顺序排列。第二行至第2n行为哈夫曼树的存储结构的终态(形如教材139页表5.2(b),一行当中的数据用空格分隔)。第2n+1行为每个字符的哈夫曼编码(只输出存在的字符,格式为:字符:编码),每两组字符之间用一个空格分隔,字符按照ASCII码从小到大的顺序排列。第2n+2行为编码后的字符串,第2n+3行为解码后的字符串(与输入的字符串相同)。
样例输入1 复制
aaaaaaabbbbbccdddd
aabccc
0
样例输出1
a:7 b:5 c:2 d:4
1 7 7 0 0
2 5 6 0 0
3 2 5 0 0
4 4 5 0 0
5 6 6 3 4
6 11 7 2 5
7 18 0 1 6
a:0 b:10 c:110 d:111
00000001010101010110110111111111111
aaaaaaabbbbbccdddd
a:2 b:1 c:3
1 2 4 0 0
2 1 4 0 0
3 3 5 0 0
4 3 5 2 1
5 6 0 3 4
a:11 b:10 c:0
111110000
aabccc
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178
| #include<iostream> #include<cstring> #include<string> using namespace std; #define MAXSIZE 1000 typedef struct { int weight; int parent,lchild,rchild; }HTNode,*HuffmanTree; typedef struct { char ss[31]; //哈夫曼编码数组,设31是为了以防二进制编码过长 int start; }HCode; void Select(HuffmanTree &HT,int m,int &ll,int &rr)//ll的weight小于等于rr的weight,且在数组中又先后顺序。 { int maxsize=1000; //判断大小的最大值 for(int i=1;i<=m;i++) { if(HT[i].parent==0&&maxsize>HT[i].weight)//为>,不是>=,保证遇到第一个编号保留下来。 { ll=i; maxsize=HT[i].weight; } } maxsize=1000; for(int i=1;i<=m;i++) { if(HT[i].parent==0&&i!=ll&&maxsize>HT[i].weight)//同理不是>= { maxsize=HT[i].weight; rr=i; } } } void CreateHuffmanTree(HuffmanTree &HT,int n,int num[]) //创建哈夫曼树 { if(n<=0) return; int m=2*n-1; HT=new HTNode[m+1]; for(int i=1;i<=m;i++) { HT[i].parent=0;HT[i].rchild=0;HT[i].lchild=0; } int start=1; for(int i=0;i<26;i++) { if(num[i]>0) { HT[start++].weight=num[i]; } } for(int i=n+1;i<=m;i++) { int s1,s2; Select(HT,i-1,s1,s2); HT[s1].parent=i;HT[s2].parent=i; HT[i].lchild=s1; HT[i].rchild=s2; HT[i].weight=HT[s1].weight+HT[s2].weight; } } void CreateHCode(HuffmanTree &HT,HCode s[],int num[],int n) { int jstart=1; //哈弗曼编号,即在HT数组里面存在 for(int i=0;i<26;i++) { s[i].start=30; //给start初始化 if(num[i]>0) { int jj=jstart; if(n==1) //控制如果为一个节点的特殊情况如何编码 s[i].ss[s[i].start--]='0'; else { while(HT[jj].parent!=0) { if(HT[HT[jj].parent].lchild==jj) {s[i].ss[s[i].start--]='0'; //编码是一个入栈,出栈的过程 jj=HT[jj].parent; } else {s[i].ss[s[i].start--]='1'; jj=HT[jj].parent; } } } jstart++; } } } int main() { string str; int num[30]; while(cin>>str) { int n=0;//这里一定要赋值为0,不然这个n一直在循环里存在,bug都找不到,我太粗心了。 memset(num,0,sizeof(num)); if(str[0]=='0') break; for(int i=0;i<str.length();i++) { int a=int(str[i])-97; num[a]++; } char b; int j; //j为暂时变量,存储位置 for(int i=0;i<26;i++) { if(num[i]>0) //输出控制num数组很重要 { b=char(i+97); cout<<b<<":"<<num[i]; j=i; n++; break; } } for(int i=j+1;i<26;i++) { if(num[i]>0) { b=char(i+97); n++; cout<<" "<<b<<":"<<num[i]; } } cout<<endl; HuffmanTree HT; int m=2*n-1; CreateHuffmanTree(HT,n,num); for(int i=1;i<=m;i++) { cout<<i<<" "<<HT[i].weight<<" "<<HT[i].parent<<" "<<HT[i].lchild<<" "<<HT[i].rchild<<endl; } HCode s[30]; //26个字母的哈夫曼编码 CreateHCode(HT,s,num,n); for(int i=0;i<26;i++) { if(num[i]>0) { b=char(i+97); cout<<b<<":"; for(int k=s[i].start+1;k<=30;k++) { cout<<s[i].ss[k]; } j=i; break;} } for(int i=j+1;i<26;i++) { if(num[i]>0) { b=char(i+97); cout<<" "<<b<<":"; for(int k=s[i].start+1;k<=30;k++) { cout<<s[i].ss[k]; } } } cout<<endl; for(int i=0;i<str.length();i++) { int p=int(str[i])-97; for(int k=s[p].start+1;k<=30;k++) cout<<s[p].ss[k]; } cout<<endl; cout<<str<<endl; str.clear(); } return 0; }
|