1、问题描述
给定n个字符及其对应的权值,构造Huffman树,并进行huffman编码和译(解)码。
构造Huffman树时,要求左子树根的权值小于、等于右子树根的权值。
进行Huffman编码时,假定Huffman树的左分支上编码为‘0’,右分支上编码为‘1’。
2、算法
构造Huffman树算法:
⑴ 根据给定的n个权值(w1, w2, …, wn)构成n棵二叉树的集合F={T1, T2, …, Tn},其中每棵二叉树Ti中只有一个权值为wi的根结点。
⑵ 在F中选取两棵根结点的权值最小的树,作为左、右子树构造一棵新的二叉树,且置其根结点的权值为其左、右子树权值之和。
⑶ 在F中删除这两棵树,同时将新得到的二叉树加入F中。
(4) 重复⑵, ⑶,直到F只含一棵树为止。
3、Huffman编码算法:
⑴ 从Huffman树的每一个叶子结点开始。
⑵ 依次沿结点到根的路径,判断该结点是父亲结点的左孩子还是右孩子,如果是左孩子则得到编码‘0’,否则得到编码‘1’,先得到的编码放在后面。
⑶ 直到到达根结点,编码序列即为该叶子结点对应的Huffman编码。
4、Huffman译(解)码算法:
⑴ 指针指向Huffman树的根结点,取第一个Huffman码。
⑵ 如果Huffman码为‘0’,将指针指向当前结点的左子树的根结点;如果Huffman码为‘1’,将指针指向当前结点的右子树的根结点。
⑶ 如果指针指向的当前结点为叶子结点,则输出叶子结点对应的字符;否则,取下一个Huffman码,并返回⑵。
⑷ 如果Huffman码序列未结束,则返回⑴继续译码。
第一行~第n行,第一组测试数据各字符编码值
第n+1行,串s1的编码值
第n+2行,串s2的解码值,若解码不成功,输出error!
其它组测试数据类推
#include<iostream>
#include<string>
using namespace std;
#define maxw 9999
class HuffmanNode
{
public:
int weight;
int parent;
int left;
int right;
HuffmanNode()
{
weight=0;
parent=left=right=-1;
}
};
class HuffmanTree
{
public:
int len;///总长
int num;///元素个数
HuffmanNode *Tree;
string *HuffmanCode;
char *message;
HuffmanTree(int n,char *c,int *w)
{
num=n;
len=2*num-1;
Tree=new HuffmanNode[len];
HuffmanCode=new string[num];
message=new char[num];
CreateHuffmanTree(c,w);
}
void CreateHuffmanTree(char *c,int *w)
{
int s1=0,s2=0;
for(int i=0;i<num;i++)
{
Tree[i].weight=w[i];
}
for(int i=0;i<num;i++)
{
message[i]=c[i];
}
for(int i=0;i<len;i++)
{
if(i>=num)
Tree[i].weight=0;
Tree[i].parent=Tree[i].left=Tree[i].right=-1;
}
for(int i=num;i<len;i++)
{
SelectMin(i-1,s1,s2);
Tree[s1].parent=i;
Tree[s2].parent=i;
Tree[i].left=s1;
Tree[i].right=s2;
Tree[i].weight=Tree[s1].weight+Tree[s2].weight;
}
}
void SelectMin(int pos,int &s1,int &s2)
{
int w1=maxw,w2=maxw;
for(int i=0;i<=pos;i++)
{
if(Tree[i].weight<w1&&Tree[i].parent==-1)
{
w1=Tree[i].weight;
s1=i;
}
}
for(int i=0;i<=pos;i++)
{
if(i==s1)
continue;
if(Tree[i].weight<w2&&Tree[i].parent==-1)
{
w2=Tree[i].weight;
s2=i;
}
}
}
void HuffmanCoding()
{
char *cd=new char[num];
cd[num-1]=‘\0‘;
int start;
for(int i=0;i<num;i++)
{
start=num-1;
for(int j=i,k=Tree[i].parent;k!=-1;j=k,k=Tree[k].parent)
{
if(Tree[k].left==j)
{
start--;
cd[start]=‘0‘;
}
else
{
start--;
cd[start]=‘1‘;
}
HuffmanCode[i].assign(&cd[start]);
}
}
}
string code(string str)
{
string coding="";
int length=str.size();
for(int i=0;i<length;i++)
{
char c=str[i];
for(int j=0;j<num;j++)
{
if(c==message[j])
{
coding+=HuffmanCode[j];
}
}
}
return coding;
}
string decode(string str)
{
string decoding="";
string iter="";
int length=str.size();
int judge1=0;
for(int i=0;i<length;i++)
{
iter+=str[i];
for(int j=0;j<num;j++)
{
if(iter==HuffmanCode[j])
{
decoding+=message[j];
judge1+=(int)iter.size();
iter="";
}
}
}
int judge2=iter.size();
if(judge1!=length)
return "error!";
if(judge2!=0)
return "error!";
return decoding;
}
};
int main()
{
int T;
cin>>T;
while(T--)
{
int n;
cin>>n;
char *c=new char[n];
for(int i=0;i<n;i++)
cin>>c[i];
int *w=new int[n];
for(int i=0;i<n;i++)
cin>>w[i];
HuffmanTree Tree(n,c,w);
Tree.HuffmanCoding();
string codeneeding,decodeneeding;
cin>>codeneeding>>decodeneeding;
for(int i=0;i<Tree.num;i++)
{
cout<<Tree.message[i]<<" "<<":"<<Tree.HuffmanCode[i]<<endl;
}
cout<<Tree.code(codeneeding)<<endl;
cout<<Tree.decode(decodeneeding)<<endl;
delete []c;
delete []w;
}
return 0;
}