问题 A: 算法6-12:自底向上的赫夫曼编码

时间限制: 1 Sec  内存限制: 32 MB
提交: 26  解决: 13
 

在通讯领域,经常需要将需要传送的文字转换成由二进制字符组成的字符串。在实际应用中,由于总是希望被传送的内容总长尽可能的短,如果对每个字符设计长度不等的编码,且让内容中出现次数较多的字符采用尽可能短的编码,则整个内容的总长便可以减少。另外,需要保证任何一个字符的编码都不是另一个字符的编码前缀,这种编码成为前缀编码。

而赫夫曼编码就是一种二进制前缀编码,其从叶子到根(自底向上)逆向求出每个字符的算法可以表示如下:

在本题中,读入n个字符所对应的权值,生成赫夫曼编码,并依次输出计算出的每一个赫夫曼编码。

 

输入

输入的第一行包含一个正整数n,表示共有n个字符需要编码。其中n不超过100。

第二行中有n个用空格隔开的正整数,分别表示n个字符的权值。

输出

共n行,每行一个字符串,表示对应字符的赫夫曼编码。

样例输入

8
5 29 7 8 14 23 3 11

样例输出

0110
10
1110
1111
110
00
0111
010

提示

赫夫曼树又名最优二叉树,它是一类带权路径长度最小的二叉树。通过构造赫夫曼树,我们可以得到赫夫曼编码,从而使得通信能够得到更高的效率。在本题中,构造赫夫曼树的过程使用了从叶子到根的逆向顺序,另外,还有一种从根出发直到叶子的赫夫曼编码构造算法,这将在下一题中进行讨论。

经验总结

看代码吧= = 要学习这个代码结构,从大佬那里弄来的,真进行哈夫曼编码确实要进行建树,而编码方法有两种,这只是第一种,理解并且要学会自己写,就行啦~~

正确代码

#include <cstdio>
#include <climits>
#include <algorithm>
#include <cstring>
using namespace std;
const int maxn=110;
struct HuffNode
{
int w,parent,lchild,rchild;
}Node[maxn*2];
void SearchMin(int &a,int &b,int n)
{
int min=INT_MAX;
for(int i=0;i<n;++i)
{
if(Node[i].parent==0&&Node[i].w<min)
{
min=Node[i].w;
a=i;
}
}
min=INT_MAX;
for(int i=0;i<n;++i)
{
if(Node[i].parent==0&&Node[i].w<min&&i!=a)
{
min=Node[i].w;
b=i;
}
}
if(a>b)
{
swap(a,b);
}
}
void HuffmanCode(int n,int * w,char * * &ans)
{
for(int i=0;i<n;++i)
{
Node[i].parent=Node[i].lchild=Node[i].rchild=0;
Node[i].w=w[i];
}
for(int i=n;i<2*n-1;++i)
{
int a,b;
SearchMin(a,b,i);
Node[i].lchild=a;
Node[i].rchild=b;
Node[i].w=Node[a].w+Node[b].w;
Node[a].parent=Node[b].parent=i;
}
int c,f,index;
char temp[n];
ans=new char * [n];
for(int i=0;i<n;++i)
{
c=i;
index=n-1;
temp[index]=0;
while(Node[c].parent!=0)
{
f=Node[c].parent;
if(Node[f].lchild==c)
temp[--index]='0';
else
temp[--index]='1';
c=f;
}
ans[i]=new char[n-index];
strcpy(ans[i],temp+index);
}
}
int main()
{
int n,w[maxn];
char * * ans;
while(~scanf("%d",&n))
{
for(int i=0;i<n;++i)
{
scanf("%d",&w[i]);
}
HuffmanCode(n,w,ans);
for(int i=0;i<n;++i)
{
printf("%s\n",ans[i]);
}
}
delete ans;
return 0;
}