题目
问题 H: DS二叉树——Huffman编码与解码(不含代码框架)
时间限制: 1 Sec 内存限制: 128 MB
提交: 475 解决: 241
[提交][状态][讨论版]
题目描述
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码序列未结束,则返回⑴继续译码。
输入
第一行测试次数
第2行:第一组测试数据的字符个数n,后跟n个字符
第3行:第一组测试数据的字符权重
待编码的字符串s1
编码串s2
其它组测试数据类推
输出
第一行~第n行,第一组测试数据各字符编码值
第n+1行,串s1的编码值
第n+2行,串s2的解码值,若解码不成功,输出error!
其它组测试数据类推
样例输入
2
5 A B C D E
15 4 4 3 2
ABDEC
00000101100
4 A B C D
7 5 2 4
ABAD
1110110
样例输出
A :1
B :010
C :011
D :001
E :000
1010001000011
error!
A :0
B :10
C :110
D :111
0100111
DAC
代码块
#include <iostream>
#include <string>
using namespace std;
class HTNode
{
private:
int weight;
int parent;
int lchild;
int rchild;
public:
HTNode():weight(0),parent(0),lchild(0),rchild(0){};
~HTNode(){};
friend class HuffmanTree;
};
class HuffmanTree
{
private:
int LeafNum;
HTNode *HT;
char *str1;
int *str2;
string *HC;
void Select(int pos, int *s1, int *s2);
public:
HuffmanTree();
~HuffmanTree();
void CreateTree();
void HuffmanCoding();
void EnCoding(string str);
void DeCoding(string str);
};
HuffmanTree::HuffmanTree()
{
int i;
cin>>LeafNum;
HC = new string[LeafNum];
str1 = new char[LeafNum];
for(i=0; i<LeafNum; i++)
cin>>str1[i];
str2 = new int[LeafNum];
for(i=0; i<LeafNum; i++)
cin>>str2[i];
HT = new HTNode[2*LeafNum];
for(int i=1; i<=LeafNum; i++)
HT[i].weight = str2[i-1];
}
HuffmanTree::~HuffmanTree()
{
delete []HC;
delete []str1;
delete []str2;
delete []HT;
LeafNum = 0;
HT = NULL, HC = NULL, str1 = NULL, str2 = NULL;
}
void HuffmanTree::Select(int pos, int *s1, int *s2)
{
int i;
int w1 = 99999, w2 = 99999;
for(i=1; i<=pos; i++)
{
if(HT[i].parent==0)
{
if(HT[i].weight<w1)
{
w1 = HT[i].weight;
*s1 = i;
}
}
}
for(i=1; i<=pos; i++)
{
if(HT[i].parent==0 && i!=*s1)
{
if(HT[i].weight<w2)
{
w2 = HT[i].weight;
*s2 = i;
}
}
}
}
void HuffmanTree::CreateTree()
{
for(int i=LeafNum+1; i<2*LeafNum; i++)
{
int s1, s2;
Select(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 HuffmanTree::HuffmanCoding()
{
for(int i=0; i<LeafNum; i++)
{
int m = i+1;
int n = HT[m].parent;
while(n!=0)
{
if(HT[n].lchild==m)
HC[i] = '0'+HC[i];
else
HC[i] = '1'+HC[i];
m = n;
n = HT[m].parent;
}
cout<<str1[i]<<" :"<<HC[i]<<endl;
}
}
void HuffmanTree::EnCoding(string str)
{
int len = str.length();
for(int i=0; i<len; i++)
{
for(int j=0; j<LeafNum; j++)
{
if(str1[j]==str[i])
cout<<HC[j];
}
}
cout<<endl;
}
void HuffmanTree::DeCoding(string str)
{
int len = str.length();
int pos = 2*LeafNum-1;
string temp;
for(int i=0; i<len; i++)
{
if(str[i]=='0')
pos = HT[pos].lchild;
else
pos = HT[pos].rchild;
if(pos<=LeafNum)
{
temp += str1[pos-1];
pos = 2*LeafNum-1;
}
}
if(pos!=2*LeafNum-1)
cout<<"error!"<<endl;
else
cout<<temp<<endl;
}
int main(void)
{
int t;
cin>>t;
while(t--)
{
HuffmanTree myTree;
myTree.CreateTree();
myTree.HuffmanCoding();
string str;
cin>>str;
myTree.EnCoding(str);
cin>>str;
myTree.DeCoding(str);
}
return 0;
}