一、简介
大学期间用vc++开发的哈夫曼编码和译码的功能,完成发送端对传送数据的编码和接收端对传送来的数据的译码。哈夫曼编码/译码实现主要有四个功能模板:一是创建哈夫曼树,从终端输入字符集大小为n,即n个字符和n个权值,建立哈夫曼树;二是输出哈夫曼树,将建立的哈夫曼树用某种树的存储方式存储后输出,即字符与编码的一一对应关系;三是哈夫曼编码,利用已建立好的哈夫曼树对输入的原文进行编码,结果存code1file.dat文件中,同时输出到屏幕;四是哈夫曼译码,利用已编码的对译文(codefile.dat中的文本)进行译码,结果存入code2file.dat文件中,同时输出到屏幕。
哈夫曼各字符的编码表:
二、详解
1、代码
(1)main.cpp
#include "stdafx.h"
#include<iostream>
#include<windows.h>//清屏和颜色管理
#include<conio.h>//getch()使用
#include<iomanip>
#include<fstream>//输入输出流处理文件
using namespace std;
ofstream outstuf;//输出流类
char filename[30];//外部文件的名字
#define MAXVALUE 50//数组的上限
#define MAXLEAF 20
#define MAXNODE MAXLEAF*2-1;
void back();
void Decode();//译码函数的声明
void getback()
{
cout<<"按任意键返回"<<endl;
getch();
back();
}
typedef struct//哈夫曼树结点的信息
{
char ch;//结点的字符
int weight;
int parent;
int lchild;
int rchild;
}HNodeType;
HNodeType HuffNode[MAXLEAF];//保存结点的数组
int n;//叶子结点的个数
HNodeType*HuffmanTree()//创建哈夫曼树
{
system("cls");
system("color 2F"); //颜色 调用doc
int i,j,m1,m2,x1,x2;
cout<<"输入叶子结点的个数!"<<endl;
cin>>n;
for(i=0;i<n*2-1;i++)//数据的初始化
{
HuffNode[i].weight=0;
HuffNode[i].parent=-1;
HuffNode[i].lchild=-1;
HuffNode[i].rchild=-1;
}
cout<<"请分别输出结点的字符和权值!"<<endl;
for(i=0;i<n;i++)//输入叶子结点的信息
cin>>HuffNode[i].ch>>HuffNode[i].weight;
for(i=0;i<n-1;i++)
{
m1=m2=MAXVALUE;
x1=x2=0;
for(j=0;j<n+i;j++)
{
if(HuffNode[j].parent==-1&&HuffNode[j].weight<m1)
{
m2=m1;
x2=x1;
m1=HuffNode[j].weight;
x1=j;
}
else
if(HuffNode[j].parent==-1&&HuffNode[j].weight<m2)
{
m2=HuffNode[j].weight;
x2=j;
}
}
HuffNode[x1].parent=n+i;
HuffNode[x2].parent=n+i;
HuffNode[n+i].weight=HuffNode[x1].weight+HuffNode[x2].weight;
HuffNode[n+i].lchild=x1;
HuffNode[n+i].rchild=x2;
}
cout<<"哈夫曼树创建成功!"<<endl;
return HuffNode;
}
void display()//哈夫曼树的输出
{
system("cls");//清屏 DOC调用
system("color 5F"); //颜色 调用doc
cout<<"****输出哈夫曼树!*****"<<endl;
cout<<"字符 "<<"权值 "<<"左孩子指针 "<<"右孩子指针"<<"父亲指针"<<endl;
for(int i=0;i<2*n-1;i++)
cout<<HuffNode[i].ch<<setw(5)<<HuffNode[i].weight<<setw(5)<<
HuffNode[i].lchild<<setw(5)<<HuffNode[i].rchild<<setw(5)<<
HuffNode[i].parent<<endl;
getback();
}
#define MAXBiT 50
typedef struct//编码的保存结构体
{
int bit[MAXBiT];
int start;
}HCodetype;HCodetype HuffCode[MAXLEAF];//编码的数组定义
void HaffmanCode()//字符的编码
{
system("cls");//清屏 DOC调用
system("color 4F"); //颜色 调用doc
HCodetype cd;
int i,j,c,p;char ch;
for(i=0;i<n;i++)
{
cd.start=n-1;
c=i;
p=HuffNode[c].parent;
while(p!=-1)
{
if(HuffNode[p].lchild==c)
cd.bit[cd.start]=0;
else
cd.bit[cd.start]=1;
cd.start--;
c=p;
p=HuffNode[c].parent;
}
for(j=cd.start+1;j<n;j++)
HuffCode[i].bit[j]=cd.bit[j];
HuffCode[i].start=cd.start;
}
cout<<"输出哈夫曼编码:"<<endl;
for(i=0;i<n;i++)
{cout<<HuffNode[i].ch<<": ";
for(j=HuffCode[i].start+1;j<n;j++)
cout<<HuffCode[i].bit[j]<<" ";
cout<<endl;
}
char hi;int m=0;char name[100];//记录输入的字符
cout<<"请输入您要编码的字符(以@为结束符)!"<<endl;
cin>>hi;
while(hi!='@')
{
int k=0;
while(HuffNode[k].ch!=hi&&k<n)
k++;
if(k==n)
{cout<<hi<<" 该字符不在哈夫曼树中!"<<endl;
cout<<"按任意键返回重新输入!"<<endl;
getch();
HaffmanCode();
}
name[m]=hi;//输入的字符进行记录
cin>>hi;
m++;
}
cout<<"哈夫曼的编码为 :"<<endl;
for( p=0;p<m;p++)
{for(int r=0;r<n;r++)
if(name[p]==HuffNode[r].ch)
{for(j=HuffCode[r].start+1;j<n;j++)
cout<<HuffCode[r].bit[j];}
}
cout<<endl;
cout<<"****您是否保存文件(Y||N)?***"<<endl;
cin>>ch;
if(ch=='y'||ch=='Y')
{
cout<<"请输入文件名!"<<endl;
cin>>filename;
outstuf.open(filename,ios::out);//打开文件
outstuf<<"哈夫曼原码: ";
for(int t=0;t<m;t++)//将数据写入文件
outstuf<<name[t]<<" ";
outstuf<<endl;
for( p=0;p<m;p++)
{for(int r=0;r<n;r++)
if(name[p]==HuffNode[r].ch)
{for(j=HuffCode[r].start+1;j<n;j++)
outstuf<<HuffCode[r].bit[j]<<" ";}
}
cout<<"保存成功!"<<endl;
outstuf.close(); //关闭文件
}
getback();//返回界面
}
int a[100];int d;//记录数组下标的全局变量
void HaffmanDecode()
{
system("cls");//清屏 DOC调用
system("color 5F"); //颜色 调用doc
cout<<"0、返回主界面 "<<"1、打开文件 "<<"2、输入需编译的序列"<<endl;
cout<<"请输入操作选择:";
int i;
cin>>i;
if(i>2||i<0) //输入超出范围控制
{
cout<<"输入有误!"<<endl;
HaffmanDecode();
}
switch(i)
{
case 0:getback();break;
case 1:
{char s[80],filename[80]; d=0;
cout<<"打开保存的文件:"<<endl;
cout<<"输入文件名:";
cin>>filename;
ifstream instuf(filename,ios::in);//打开文件
if(!instuf)
{cout<<"文件不能打开!"<<endl;
getback();
}
instuf.getline(s,80);
while(instuf>>a[d])
d++;
a[d]=2;
cout<<"文件中哈夫曼编码输出!"<<endl;
for(int r=0;r<d;r++)
cout<<a[r]<<" ";
cout<<endl;
if(a[0]!=0&&a[0]!=1)
{cout<<"此文件无内容!";
getback();
}
instuf.close();
Decode();
}break;
case 2:{int ao;d=0;
cout<<"请输入需译码的的(0和1)代码,以2为结束码!"<<endl;
cin>>ao;//输入代码
while(ao!=2)
{ if(ao!=0&&ao!=1)
{cout<<ao<<" 该译码不在哈夫曼树中!"<<endl;
cout<<"按任意键返回重新输入!"<<endl;
getch();
HaffmanDecode();
}
a[d]=ao;//将代码保存到数组中
cin>>ao;
d++;
}
a[d]=2;//定义结束符(以2结束)
Decode();
}
break;
}
}
void Decode()//译码过程
{
char hi;
cout<<"请问您是在原基础上译码吗?"<<endl;
cout<<"若已有哈夫曼树则跳过此步(N||n),若无则进入(Y||y)"<<endl;
cin>>hi;
if(hi=='Y'||hi=='y')//建立新的哈夫曼树
{
cout<<"进入则建立共有的编译原则,即建立相同的哈夫曼树!"<<endl;
HuffmanTree();
}
int p;int j=0,k=0;char zu[100];char ch2;
while(a[j]!=2)//对0、1代码进行译码
{
p=2*n-2;
while(HuffNode[p].lchild!=-1&&HuffNode[p].rchild!=-1)
{
if(HuffNode[p].lchild!=-1&&HuffNode[p].rchild!=-1&&a[j]==2)
{ cout<<"此序列输入有误,请检查后重新输入!"<<endl;
cout<<"按任意键返回重新输入!"<<endl;
getch();
HaffmanDecode();
}
if(a[j]==0) p=HuffNode[p].lchild;
if(a[j]==1) p=HuffNode[p].rchild;
j++;
}
zu[k]=HuffNode[p].ch;//译码的字符保存
k++;
}
cout<<"编码的译码为:"<<endl;
for(int t=0;t<k;t++)
cout<<zu[t]<<" ";
cout<<endl;
cout<<"****您是否保存文件(Y||N)?***"<<endl;
cin>>ch2;
if(ch2=='y'||ch2=='Y')
{
cout<<"请输入文件名!"<<endl;
cin>>filename;
outstuf.open(filename,ios::out);
outstuf<<"哈夫曼译码: "<<endl;
for(int w=0;w<k;w++)//将译码写入文件
{
outstuf<<zu[w]<<" ";
}
cout<<endl;
cout<<"保存成功!"<<endl;
outstuf.close();
}
cout<<"按任意键返回"<<endl;
getch();
HaffmanDecode();
}
void back()//哈夫曼树的主界面
{
system("cls");//清屏 DOC调用
system("color 3F"); //颜色 调用doc
cout<<"0、退出."<<setw(20)<<"1、创建哈夫曼树."<<setw(20)
<<"2、输出哈夫曼树."<<setw(15)<<"3、哈夫曼编码."<<setw(15)<<"4、哈夫曼译码."<<endl;
cout<<"请输入操作选择:";
int i;
cin>>i;
if(i>4||i<0) //输入超出范围控制
{
cout<<"输入有误!"<<endl;
getback();
}
switch(i)//不同路径的选择
{
case 1:HuffmanTree();getback();;break;
case 2:display();break;
case 3:HaffmanCode();break;
case 4:HaffmanDecode();break;
case 0:exit(0);break;
default:cout<<"你的输入有误!\n";
}
}
void main()//主函数
{
system("color 1F"); //颜色 调用doc
char ch;
cout<<"*****您想进入哈夫曼编码译码实现管理系统!****"<<endl;
cout<<"->->->若进入请按Y,若不进入请按N.<-<-<-"<<endl;
cin>>ch;
if(ch=='Y'||ch=='y')
back();
else
cout<<"您已退出系统!"<<endl;
}
(2)编译运行
在vc6.0或vs2010上都能编译通过:
三、总结
(1)上述代码仅仅用来回忆学习C++的过程。
(2)若有建议,请留言,在此先感谢!