关闭

linux下c/c++实例之十七哈夫曼编码译码实现

标签: linuxcc++
771人阅读 评论(0) 收藏 举报
分类:

一、简介

      大学期间用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)若有建议,请留言,在此先感谢!
0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:1340143次
    • 积分:13190
    • 等级:
    • 排名:第995名
    • 原创:268篇
    • 转载:96篇
    • 译文:0篇
    • 评论:289条
    最新评论