1760 Problem A 算法6-12:自底向上的赫夫曼编码
原创
©著作权归作者所有:来自51CTO博客作者漫浸天空的雨色的原创作品,请联系作者获取转载授权,否则将追究法律责任
问题 A: 算法6-12:自底向上的赫夫曼编码
时间限制: 1 Sec 内存限制: 32 MB
提交: 26 解决: 13
在通讯领域,经常需要将需要传送的文字转换成由二进制字符组成的字符串。在实际应用中,由于总是希望被传送的内容总长尽可能的短,如果对每个字符设计长度不等的编码,且让内容中出现次数较多的字符采用尽可能短的编码,则整个内容的总长便可以减少。另外,需要保证任何一个字符的编码都不是另一个字符的编码前缀,这种编码成为前缀编码。
而赫夫曼编码就是一种二进制前缀编码,其从叶子到根(自底向上)逆向求出每个字符的算法可以表示如下:
在本题中,读入n个字符所对应的权值,生成赫夫曼编码,并依次输出计算出的每一个赫夫曼编码。
输入
输入的第一行包含一个正整数n,表示共有n个字符需要编码。其中n不超过100。
第二行中有n个用空格隔开的正整数,分别表示n个字符的权值。
输出
共n行,每行一个字符串,表示对应字符的赫夫曼编码。
样例输入
样例输出
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;
}