一、实验内容
给定报文中26个字母a-z及空格的出现频率{64, 13, 22, 32, 103, 21, 15, 47, 57, 1, 5, 32, 20, 57, 63, 15, 1, 48, 51, 80, 23, 8, 18, 1, 16, 1, 168},构建哈夫曼树并为这27个字符编制哈夫曼编码,并输出。模拟发送端,从键盘输入字符串,以%为结束标记,在屏幕上输出输入串的编码;模拟接收端,从键盘上输入0-1哈夫曼编码串,翻译出对应的原文。
参考界面:
二、验收/测试用例
模拟发送端
输入:I love you
输出:01101111011110011100000010111100011100100001
模拟接收端 输入
输入:01101101111011000111111010111101101001100001
输出:it is a dog
三、代码示例
#include <iostream>
#include<cstring>
using namespace std;
static int c1,c2; //编码,译码时计数
//哈夫曼编码表的存储表示
typedef char **HuffmanCode; //动态分配数组存储哈夫曼编码表
//哈夫曼树的存储表示
typedef struct
{
int weight; //结点的权值
int parent,lchild,rchild; //结点的双亲,左孩子,右孩子的下标
} HTNode,*HuffmanTree;
/*从HT[1]到HT[j]中选择parent为0且weight最小的两个结点,用s1和s2返回其序号*/
void Select(HuffmanTree HT, int j, int *s1, int *s2)
{
int i;
//找weight最小的结点
for (i = 1; i <= j; i++)
if (HT[i].parent == 0)
{
*s1 = i;
break;
}
for (; i <= j; i++)
if ((HT[i].parent == 0) && (HT[i].weight < HT[*s1].weight))
*s1 = i;
HT[*s1].parent = 1;
//找weight次小的结点
for (i = 1; i <= j; i++)
if (HT[i].parent == 0)
{
*s2 = i;
break;
}
for (; i <= j; i++)
if ((HT[i].parent == 0) && (i != *s1) && (HT[i].weight < HT[*s2].weight))
*s2 = i;
}
//构造哈夫曼树
void CreatHuffmanTree(HuffmanTree &HT,int n)
{
//构造哈夫曼树HT
int m=2*n-1;
HT=new HTNode[m+1]; //0号单元未用,所以需要动态分配m+1个单元,HT[m]表示根节点
for(int i=1; i<=m; i++) //将1~m号单元中的双亲,左孩子,右孩子的下标都初始化为0
{
HT[i].parent=0;
HT[i].lchild=0;
HT[i].rchild=0;
}
for(int i=1; i<=n; i++) //输入前n个单元中叶子结点的权值
cin>>HT[i].weight;
/*-------------------初始化工作结束,下面开始创建哈夫曼树----------------*/
for(int i=n+1; i<=m; i++)
{
//通过n-1次的选择,删除,合并来创建哈夫曼树
int s1=0,s2=0;
Select(HT,i-1,&s1,&s2); //在HT[k](1<=k<=i-1)中选择两个其双亲域为0且权值最小的结点,并返回他们在HT中的序号s1和s2
HT[s1].parent=i;
HT[s2].parent=i; //得到新结点i,从森林中删除s1,s2,将s1和s2的双亲域由0改i
HT[i].lchild=s1;
HT[i].rchild=s2; //s1,s2分别作为i的左右孩子
HT[i].weight=HT[s1].weight+HT[s2].weight; //i的权值为左右孩子权值之和
}
}
//创建编码表
void CreatHuffmanCode(HuffmanTree HT,HuffmanCode &HC,int n)
{
int start,c,f;
HC=new char*[n+1]; //分配存储字符编码的存储空间
char *cd=new char[n]; //临时分配存放每个字符的动态数组空间
cd[n-1]='\0'; //编码结束符
for(int i=1; i<=n; i++)
{
start = n-1;
c=i;
f=HT[c].parent;
while(f!=0)
{
start--;
if(HT[f].lchild==c)
{
cd[start]='0';
}
else
{
cd[start]='1';
}
c=f;
f=HT[f].parent;
}
HC[i] = new char[n-start];
strcpy(HC[i],&cd[start]);
}
delete cd;
}
//译码
void DeCode(HuffmanTree HT,char a[],char ch[],char b[],int n)
{
c1=0;
int q=2*n-1;
int k=0;
for(int i=0; a[i]!='#'; i++)
{
if(a[i]=='0')
{
q=HT[q].lchild;
}
else if(a[i]=='1')
{
q=HT[q].rchild;
}
if(HT[q].lchild==0 && HT[q].rchild==0)
{
b[k++]=ch[q-1];
q=2*n-1;
}
}
c1=k;
b[k]='\0';
}
void show_help()
{
cout<<"******************************************************************"<<endl;
cout<<"********** 1.输入HuffmanTree的参数 **********"<<endl;
cout<<"********** 2.初始化HuffmanTree参数(含有26字母及空格) **********"<<endl;
cout<<"********** 3.创建HuffmanTree和编码表 **********"<<endl;
cout<<"********** 4.输出编码表 **********"<<endl;
cout<<"********** 5.输入编码,并翻译为字符 **********"<<endl;
cout<<"********** 6.输入字符,并实现转码 **********"<<endl;
cout<<"********** 7.退出 **********"<<endl;
cout<<"******************************************************************"<<endl;
}
int main()
{
char operate_code;
HuffmanTree HT;
HuffmanCode HC;
char a[1000]; //译码时存放二进制编码
char b[1000]; //存放译码后的字符
char c[1000]; //编码时存放输入字符
int n; //表示编码字符个数
char ch[27]= {'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z',' '};
show_help();
while(1)
{
cout<<"请输入操作选项: ";
cin>>operate_code;
if(operate_code=='1')
{
cout<<"请输入编码字符个数:";
cin>>n;
}
else if (operate_code=='2')
{
cout<<"请输入编码字符权值:";
CreatHuffmanTree(HT,n);
cout<<"初始化成功"<<endl;
}
else if (operate_code=='3')
{
CreatHuffmanCode(HT,HC,n);
cout<<"创建成功"<<endl;
}
else if (operate_code=='4')
{
cout<<"结点"<<"\t"<<"字符"<<"\t"<<"权值"<<"\t"<<"编码"<<endl;
for(int i=1; i<=n; i++)
{
cout<<i<<"\t"<<ch[i-1]<<"\t"<< HT[i].weight<<"\t"<<HC[i]<<endl;
}
cout<<endl;
}
else if (operate_code=='5')
{
cout<<"请输入二进制编码('#'表示结束): ";
for(int i=0; i<1000; i++)
{
cin>>a[i];
char data = a[i];
if(a[i]=='#')
{
break;
}
}
DeCode(HT,a,ch,b,n);
cout<<"输出:";
for(int i=0; i<c1; i++)
{
cout<<b[i];
}
cout<<endl;
}
else if (operate_code=='6')
{
c2=0;
cout<<"请输入要编码的字符('#'表示结束): ";
for(int i=0;i<1000;i++)
{
cin>>c[i];
char data = c[1];
c2++;
if(c[i]=='#')
{
break;
}
}
cout<<"输出: ";
for(int i=0;i<c2-1;i++)
{
for(int j=0;j<n;j++)
{
if(c[i]==ch[j])
{
cout<<HC[j+1];
break;
}
}
}
cout<<endl;
}
else if (operate_code=='7')
{
break;
}
else
{
cout<<"\n操作码错误!!!"<<endl;
show_help();
}
}
return 0;
}