哈夫曼编码与译码
总提交:386 测试通过:141
描述
已知电文包括的字符集为{A,C,I,M,N,P,T,U},输入对应权值,对字符集合进行哈夫曼编码,完成电文的哈夫曼编码与译码工作。
输入
共三行:
第一行为对应字符集{A,C,I,M,N,P,T,U}的权值
第二行为一段字符串表示的电文(长度不超过1000);
第三行为一段电文的哈夫曼编码。
输出
共十行:
前八行为各字符的编码;
第九行是与第二行输入对应的哈夫曼编码;
第十行是与第三行输入对应的电文。
样例输入
1 2 3 4 5 6 7 8
NUPTICPCACM
1111011111100
样例输出
A: 11110
C: 11111
I: 1110
M: 100
N: 101
P: 110
T: 00
U: 01
1010111000111011111110111111111011111100
ACM
提示
2012.4.11 更新
题目来源
NUPT ACM
分析:以前只了解哈夫曼树的原理,没想到实现起来遇到了不少难题。首先要创建一个哈夫曼树节点类,包含权重(weight)、英文字符(data),内部定义了构造函数。链表实现左孩子和右孩子。
创建哈夫曼树原理:取权值最小的2个,合并生成一个新的节点,新的节点的权值为2个孩子的权值的和。重复直到只有一个根节点。
C++实现运用priority_queue,并且重写了compare方法(选取权值最小的),priority_queue用了top、pop、push函数。然后也是很关键的编码,编码利用递归将英文字符的编码保存在二维数组int code[x][1]~code[x][m]中,x代表字符的ASCII码,m代表该英文字符的编码的位数,以此来区分,利用了int tmp[]数组存放临时的0/1。
编码原理:左边为0,右边为1。
输出即为code[ str[i] ][j]
译码逐个分析输入的字符串,并且利用建立的哈夫曼树,从哈夫曼树的根节点开始,输入为1指向右孩子,输入位0指向左孩子。然后判断该节点的英文字符(data)是否为'0',因为只有叶子节点的data为('A'/'C'/'I'/'M'...),而合并的节点初始化data为字符'0'。以此来判断是否出现了匹配的英文字符。别忘了队列要重置p = myQueue.top();
还是有细节问题。关于哈夫曼树写法也有很多。
#include<iostream>
#include<queue>
#include<string>
using namespace std;
#define MAX 10
//哈夫曼编码与译码
char str[8] = {'A','C','I','M','N','P','T','U'};
int tmp[MAX*3];
int code[256][MAX*3]; // code[A][0]~code[A][m] = 100111...'A'——ASCII码
string strInput;
class HTNode
{
public:
int weight; // 权重 1/2/3...
char data; // A/C/I...
HTNode *lChild, *rChild;
HTNode()
{
data = '0';
weight = 0;lChild = rChild = NULL;
}
HTNode(int a,char s)
{
weight = a; lChild=rChild = NULL;
data = s;
}
};
HTNode* uni(HTNode *p,HTNode *q) // p、q合并
{
HTNode *tmp = new HTNode(p->weight + q->weight, '0');
tmp->lChild = p;
tmp->rChild = q;
return tmp;
}
// 哈夫曼编码 递归
void bianma(HTNode *p,int m)
{
if(p->rChild == NULL)
{
code[p->data][0] = m; // 编码为多少位
for(int i=1;i<=m;i++)
{
code[p->data][i] = tmp[i-1];
}
}
else
{
tmp[m] = 0;
bianma(p->lChild,m+1); // 左0
tmp[m] = 1;
bianma(p->rChild,m+1); // 右1
}
}
//用于实现优先级的比较函数
class HTNodeCmp
{
public:
bool operator()(HTNode* p1, HTNode* p2) const
{
return p1->weight > p2->weight;
}
};
/*
//层次遍历 输出节点的权值
void LevelOrder(HTNode *&t)
{
int front = 0, rear = 1;
HTNode *p[100];
p[0] = t;
while(front < rear)
{
if(p[front])
{
cout<<" "<<p[front]->weight;
p[rear++] = p[front]->lChild;
p[rear++] = p[front]->rChild;
front ++;
}
else
front ++;
}
}
*/
priority_queue<HTNode *, deque<HTNode *>, HTNodeCmp> myQueue;
int main()
{
int i,a;
for(i=0;i<8;i++)
{
cin>>a;
HTNode *p;
p = new HTNode(a, str[i]); // 自动构造 8个节点
myQueue.push(p); // 加入一个元素
}
while(myQueue.size()>1) // >1,只剩根节点
{
HTNode *p, *q, *k;
p = myQueue.top(); // 权值最小的
//cout<<p->weight<<" ";
myQueue.pop(); // 调用pop删除这个元素
q = myQueue.top(); // 权值最小的
//cout<<q->weight<<endl;
myQueue.pop();
k = uni(p, q); // key!
myQueue.push(k);
}
HTNode *p = myQueue.top(); // 权值最大的
bianma(p, 0); // 编码
for(i=0;i<8;i++)
{
cout<<str[i]<<": ";
for(int j=1;j<=code[str[i]][0];j++)
{
cout<<code[ str[i] ][j];
}
cout<<endl;
}
//LevelOrder(p);
cin>>strInput;
int len = strInput.length();
for(i=0;i<len;i++)
{
for(int j=1;j<=code[strInput[i]][0];j++)
{
cout<<code[strInput[i]][j];
}
}
cout<<endl;
//译码
cin>>strInput;
len = strInput.length();
HTNode *q = myQueue.top();
for(i=0;i<len;i++)
{
if(strInput[i] == '1')
{
q = q->rChild;
}
else
{
q = q->lChild;
}
if(q->data != '0') // 找到对应的字母
{
cout<<q->data;
q = myQueue.top(); // 重置q 队列
}
}
cout<<endl;
return 0;
}
哈夫曼编码与译码实现详解

本文介绍如何对字符集{A,C,I,M,N,P,T,U}进行哈夫曼编码和译码,详细解析哈夫曼树的构建过程,以及C++实现中的关键步骤,包括使用priority_queue和自定义比较函数。同时提供了一个样例,展示编码和译码的实际应用。
5283

被折叠的 条评论
为什么被折叠?



