模拟编码译码(huffman编码应用)

用huffman编码对一些字符进行编码,然后再将用户输入的桔子进行编码,还有译码等。一个huffman 编码的小应用

文件"huffman.h"

#include <iostream>
#include <string>
#include <fstream>
using namespace std;

//栈模版
template<class T>
class My_stack;

template<class T>
class Node		//结点类
{
private:
	T data;
	Node<T> *next;
public:
	Node()
	{
		next=NULL;
	}
	Node(T d)
	{
		data=d;
		next=NULL;
	}
	friend My_stack<T>;
};

template<class T>
class My_stack
{
private:
	Node<T> *head;
public:
	My_stack()
	{
		head=new Node<T>();
	}
	
	~My_stack()
	{
		clean();
		delete head;
	}
	
	bool empty() const
	{
		return (head->next==0);
	}
	
	void push(T d)	//入栈
	{
		Node<T> *p=new Node<T>(d);
		p->next=head->next;
		head->next=p;
	}
	
	T top()	//返回栈顶元素
	{
		if(empty())
		{
			cout<<"stack is empty."<<endl;
			exit(1);
		}
		Node<T> *p=head->next;
		T temp=p->data;
		return temp;
	}
	
	void pop()	//弹出栈顶元素
	{
		Node<T> *p=head->next;
		head->next=p->next;
		delete p;
	}
	
	void clean()	//清除整个栈
	{
		Node<T> *p=head->next;
		while(p)
		{
			head->next=p->next;
			delete p;
			head->next=p;
		}
	}
};

//临时结点结构,存放哈夫曼树的结点名称和数据
struct temp_node
{
	char name;
	int data;
};

//临时结点结构,用于存放编码后的结点名称和数据
struct EnCo_Node
{
	char name;
	string data;
};

class HuffmanTree;

class HuffmanNode
{
private:
	char name;
	int data;
	int parent,lchild,rchild;
	friend HuffmanTree;
};

class HuffmanTree
{
public:
	void Create_HuffmanTree(HuffmanNode *&HT,temp_node w[],int n)
	{
		//用w申请的数组暂时保存权值(暂时设定全都大于0)
		if(n<1)
		{
			cout<<"参数不合理"<<endl;
			return ;
		}
		
		int m=2*n-1; //n个叶子结点的哈夫曼树总共有2*n-1个结点
		
		HT=new HuffmanNode[m]; //分配m个huffman结点
		
		int i,k,lnode,rnode;
		double min1,min2; //存放两个最小的结点值
		for(i=0;i<n;i++)
		{
			HT[i].name=w[i].name;
			HT[i].data=w[i].data;
			HT[i].lchild=-1;
			HT[i].rchild=-1;
			HT[i].parent=-1;
		}
		for(int j=i;j<m;j++)
		{
			HT[j].name='#';
			HT[j].data=0;
			HT[j].lchild=-1;
			HT[j].rchild=-1;
			HT[j].parent=-1;
		}
		//结点初始化完成,下面开始构造huffman树	
		for(i=n;i<2*n-1;i++)
		{		
			min1=min2=32767;
			lnode=rnode=-1;
			for(k=0;k<=i-1;k++)
			{
				if(-1 == HT[k].parent)
				{
					if(HT[k].data<min1)
					{
						min2=min1;
						rnode=lnode;
						min1=HT[k].data;
						lnode=k;
					}
					else if(HT[k].data<min2)
					{
						min2=HT[k].data;
						rnode=k;
					}
				}
			}
			HT[i].data=min1+min2;
			HT[i].lchild=lnode;
			HT[i].rchild=rnode;
			HT[lnode].parent=i;
			HT[rnode].parent=i;
		}
		cout<<"____huffman树构造完成____"<<endl;
	}

	void Huffman_Coding(HuffmanNode *HT,int n)
	{
		//对结点进行哈夫曼编码
		ofstream file;
		HuffmanNode *q;
		int f,temp,p,a[20],t;
		My_stack<int> s;
		file.open("hfmTree.txt");
		for(int i=0;i<n;i++)
		{	
			t=0;
			q=HT;
			f=i;
			p=q[f].parent;
			while(p!=-1)
			{
				if(q[p].lchild==f)
					temp=0;
				else
					temp=1;
				s.push(temp);
				f=p;
				p=q[p].parent;
			}
			cout<<"第"<<i+1<<"个字符 "<<HT[i].name<<" 的huffman编码为:";
			while(!s.empty())
			{
				cout<<s.top()<<" ";
				a[t]=s.top();
				t++;
				s.pop();
			}
			//将各个字符的编码存入指定文件中
			Save_Code(a,t,HT[i].name);
			cout<<endl;
		}
		file.close();
		cout<<"编码完成,并已保存到\"hfmTree.txt\"文件中"<<endl;
	}

	//保存每一个编码到hfmTree文件中
	void Save_Code(int a[],int n,char name)
	{
		ofstream file;
		file.open("hfmTree.txt",ios::app);
		file<<endl<<name<<"   ";
		for(int i=0;i<n;i++)
			file<<a[i];
		file.close();
	}

	bool EnCoding(const char *p,int n)
	{
		//编码函数,对字符串进行编码,然后保存到指定文件
		fstream file1,file2;
		string Aim_Code[100];
		int i,sum=0;
		string temp_c;

		file1.open("hfmTree.txt",ios::in);
		if(!file1)
		{
			cerr<<"文件\"hfmTree.txt\"打开失败"<<endl;
			return false;
		}

		EnCo_Node node[30];
		for(i=0;i<30;i++)
			node[i].data="32767";

		while(!file1.eof())
		{
			file1>>node[sum].name>>node[sum].data;
			sum++;
		}
		file1.close();

		i=0;
		sum=0;
		while(p[i] != '\0')
		{
			if(p[i] == '*')
				temp_c=node[n-1].data;
			else
				temp_c=node[ p[i] - 'A' ].data;
			if(temp_c == "32767" )
				cout<<"字符 "<<p[i]<<" 没有编码,在编码文件中将不会有该字符的编码"<<endl;
			else
			{
				Aim_Code[sum]=temp_c;
				sum++;
			}
			i++;
		}
		
		file2.open("CodeFile.txt",ios::out);
		if(!file2)
		{
			cerr<<"文件\"CodeFile.txt\"打开失败"<<endl;
			return false;
		}
		for(int j=0;j<sum;j++)
			file2<<endl<<Aim_Code[j];
		file2.close();
	
		return true;
	}

	bool Decoding()
	{
		//译码函数,将文件CodeFile.txt中的编码进行编译,还原成原来的意思
		int i,j,Code_sum,Aim_sum;
		fstream file1,file2,file3;
		file1.open("hfmTree.txt",ios::in);
		if(!file1)
		{
			cerr<<"文件\"hfmTree.txt\"打开失败"<<endl;
			return false;
		}

		EnCo_Node node[30];
		Code_sum=0;
		while(!file1.eof())
		{
			file1>>node[Code_sum].name>>node[Code_sum].data;
			Code_sum++;
		}
		
		file1.close();

		file2.open("CodeFile.txt",ios::in);
		if(!file2)
		{
			cerr<<"文件\"CodeFile.txt\"打开失败"<<endl;
			return false;
		}

		string Aim_Code[100];
		Aim_sum=0;
		while(!file2.eof())
		{
			file2>>Aim_Code[Aim_sum];
			Aim_sum++;
		}
		file2.close();

		file3.open("TextFile.txt",ios::out);
		if(!file3)
		{
			cerr<<"文件\"TextFile.txt\"打开失败"<<endl;
			return false;
		}

		for(i=0;i<Aim_sum;i++)
		{
			for(j=0;j<Code_sum;j++)
			{
				if(node[j].data == Aim_Code[i])
				{
					if(node[j].name == '*')
					{
						//cout<<" ";
						file3<<" ";
					}
					else
					{
						//cout<<node[j].name;
						file3<<node[j].name;
					}
				}
			}
		}
		file3.close();

		return true;
	}

	bool Show_Code()
	{
		//紧凑形式显示编码,并存入文件
		int Code_sum,i;
		int Aim_Code[100];
		char p[256];
		fstream file1,file2,file3;
		file1.open("CodeFile.txt",ios::in);
		if(!file1)
		{
			cerr<<"文件\"CodeFile.txt\"打开失败"<<endl;
			return false;
		}

		Code_sum=0;
		while(!file1.eof())
		{
			file1>>Aim_Code[Code_sum];
			Code_sum++;
		}
		file1.close();

		file2.open("CodePrin.txt",ios::out);
		if(!file2)
		{
			cerr<<"文件\"CodePrin.txt\"打开失败"<<endl;
			return false;
		}
		
		for(i=0;i<Code_sum;i++)
			file2<<Aim_Code[i];
		file2.close();

		file2.open("CodePrin.txt",ios::in);
		if(!file2)
		{
			cerr<<"文件\"CodePrin.txt\"打开失败"<<endl;
			return false;
		}
		
		i=0;
		while(!file2.eof())
		{
			file2>>p[i];
			i++;
		}
		file2.close();

		for(int j=0;j<i;j++)
		{
			cout<<p[j];
			if(j>0 && j%49 == 0)
				cout<<endl;
		}
		cout<<endl;

		file3.open("CodePrin.txt",ios::out);
		if(!file3)
		{
			cerr<<"文件\"CodePrin.txt\"打开失败"<<endl;
			return false;
		}

		for(j=0;j<i;j++)
		{
			file3<<p[j];
			if(j>0 && j%49 == 0)
				file3<<endl;
		}
		file3.close();
		return true;
	}

	void Print_Trees(HuffmanNode *HT,int m,int n,int base,int dep)
	{
		//凹入形式显示哈夫曼树
		if(dep>0)
		{
			ofstream file("TreePrint.txt",ios::app);
			int b=base-dep;
			for(int i=b;i>0;i--)
			{
				cout<<"   ";
				file<<"   ";
			}
			cout<<HT[m-1].data<<endl;
			file<<HT[m-1].data<<endl;
			file.close();
			if(m>n)
			{
				Print_Trees(HT,HT[m-1].lchild+1,n,base,dep-1);
				Print_Trees(HT,HT[m-1].rchild+1,n,base,dep-1);
			}
		}
	}
};
主函数:

#include "huffman.h"
#include <fstream>
#include <string>
#include <iostream>
using namespace std;

int main()
{
	int flag,n=0,i,m=0,dep;
	long pos;
	temp_node *p;
	HuffmanTree tree;
	HuffmanNode *HT;
	fstream file1,file2;
	do
	{
		cout<<"输入你的选择:"<<endl;
		cout<<"*********************************************"<<endl;
		cout<<"* 1:初始化         2:哈夫曼编码     3:译码  *"<<endl;
		cout<<"* 4:印编码文件     5:印哈夫曼树     6:退出  *"<<endl;
		cout<<"*********************************************"<<endl;
		cin>>flag;
		switch(flag)
		{
		case 1:
			n=0;
			p=new temp_node[30];
			file1.open("TreeData.txt",ios::in);
			if(!file1)
			{
				cerr<<"文件\"TreeData.txt\"打开失败"<<endl;
				exit(1);
			}
			cout<<"从文件\"TreeData.txt\"读入数据初始化"<<endl;
			while(!file1.eof())
			{
				file1>>p[n].name>>p[n].data;
				n++;
			}
			cout<<endl;
			tree.Create_HuffmanTree(HT,p,n);
			cout<<"__________huffman编码_____________并显示编码________"<<endl;
			file1.open("hfmTree.txt",ios::out);
			tree.Huffman_Coding(HT,n);
			cout<<endl;
			break;
		case 2:	
			file1.open("hfmTree.txt",ios::in);
			file1.seekg(0,ios::end);
			pos=file1.tellg();
			if(!pos)
				cout<<"哈夫曼树不存在,请先初始化哈夫曼树"<<endl;
			else
			{
				//编码
				cout<<"输入你要进行编码的字符串(空格用'*'代替):";
				string target;
				cin>>target;
				const char *ch=target.data();
				//调用译码函数
				if(tree.EnCoding(ch,n))
					cout<<"编码完成,编码结果已经存入\"CodeFile.txt\"文件中"<<endl;
			}
			file1.close();
			break;
		case 3:
            //译码
			file1.open("CodeFile.txt",ios::in);
			file1.seekg(0,ios::end);
			pos=file1.tellg();
			if(!pos)
				cout<<"待编码文件不存在,请重新进行编码,再选择译码操作"<<endl;
			else
			{
				if(tree.Decoding())
					cout<<"译码成功,译码结果已存放在文件\"TextFile.txt\"中"<<endl;
			}
			file1.close();
			break;
		case 4:
			//印编码
			file2.open("CodeFile.txt",ios::in);
			file2.seekg(0,ios::end);
			pos=file2.tellg();
			if(!pos)
				cout<<"该文件不存在,请重新进行编码,再选择此操作"<<endl;
			else
			{
				if(tree.Show_Code())
					cout<<"显示完成"<<endl;
			}
			break;
		case 5:
			cout<<"显示哈夫曼树中数据的结构,只显示权值的组成结构"<<endl;
			m=2*n-1;
			dep=m-n;
			file1.open("TreePrint.txt",ios::out);
			tree.Print_Trees(HT,m,n,m-n,dep);
			file1.close();
			cout<<endl;
			break;
		case 6:
			cout<<"谢谢使用,88"<<endl;
			break;
		default:
			cout<<"选择无效,重新选择"<<endl;
			break;
		}
	}while(flag != 6);

	return 0;
}
测试结果:

输入你的选择:
*********************************************
* 1:初始化         2:哈夫曼编码     3:译码  *
* 4:印编码文件     5:印哈夫曼树     6:退出  *
*********************************************
1
从文件"TreeData.txt"读入数据初始化

____huffman树构造完成____
__________huffman编码_____________并显示编码________
第1个字符 A 的huffman编码为:1 0 1 0
第2个字符 B 的huffman编码为:1 0 0 0 0 0
第3个字符 C 的huffman编码为:0 0 0 0 0
第4个字符 D 的huffman编码为:1 0 1 1 0
第5个字符 E 的huffman编码为:0 1 0
第6个字符 F 的huffman编码为:1 1 0 0 1 1
第7个字符 G 的huffman编码为:1 0 0 0 0 1
第8个字符 H 的huffman编码为:0 0 0 1
第9个字符 I 的huffman编码为:0 1 1 0
第10个字符 J 的huffman编码为:1 1 0 0 0 0 1 0 0 0
第11个字符 K 的huffman编码为:1 1 0 0 0 0 1 1
第12个字符 L 的huffman编码为:1 0 1 1 1
第13个字符 M 的huffman编码为:1 1 0 0 1 0
第14个字符 N 的huffman编码为:0 1 1 1
第15个字符 O 的huffman编码为:1 0 0 1
第16个字符 P 的huffman编码为:1 0 0 0 1 0
第17个字符 Q 的huffman编码为:1 1 0 0 0 0 1 0 0 1
第18个字符 R 的huffman编码为:0 0 1 0
第19个字符 S 的huffman编码为:0 0 1 1
第20个字符 T 的huffman编码为:1 1 0 1
第21个字符 U 的huffman编码为:0 0 0 0 1
第22个字符 V 的huffman编码为:1 1 0 0 0 0 0
第23个字符 W 的huffman编码为:1 1 0 0 0 1
第24个字符 X 的huffman编码为:1 1 0 0 0 0 1 0 1 0
第25个字符 Y 的huffman编码为:1 0 0 0 1 1
第26个字符 Z 的huffman编码为:1 1 0 0 0 0 1 0 1 1
第27个字符 * 的huffman编码为:1 1 1
编码完成,并已保存到"hfmTree.txt"文件中

输入你的选择:
*********************************************
* 1:初始化         2:哈夫曼编码     3:译码  *
* 4:印编码文件     5:印哈夫曼树     6:退出  *
*********************************************
2
输入你要进行编码的字符串(空格用'*'代替):
CSDN*BLOG*KAYSPRINT*COME*ON
编码完成,编码结果已经存入"CodeFile.txt"文件中
输入你的选择:
*********************************************
* 1:初始化         2:哈夫曼编码     3:译码  *
* 4:印编码文件     5:印哈夫曼树     6:退出  *
*********************************************
3
译码成功,译码结果已存放在文件"TextFile.txt"中
输入你的选择:
*********************************************
* 1:初始化         2:哈夫曼编码     3:译码  *
* 4:印编码文件     5:印哈夫曼树     6:退出  *
*********************************************
4
01110110111111100000101111001100001111110000111010
1000111110001010110111110111101001110010101111001
111
显示完成
输入你的选择:
*********************************************
* 1:初始化         2:哈夫曼编码     3:译码  *
* 4:印编码文件     5:印哈夫曼树     6:退出  *
*********************************************
5
显示哈夫曼树中数据的结构,只显示权值的组成结构
1000
   408
      191
         92
            45
               22
               23
            47
         99
            48
            51
      217
         103
         114
            57
            57
   592
      250
         122
            59
               28
                  13
                  15
               31
                  15
                  16
            63
         128
            64
            64
               32
               32
      342
         156
            76
               35
                  17
                     8
                     9
                        4
                           2
                              1
                              1
                           2
                              1
                              1
                        5
                  18
               41
                  20
                  21
            80
         186

输入你的选择:
*********************************************
* 1:初始化         2:哈夫曼编码     3:译码  *
* 4:印编码文件     5:印哈夫曼树     6:退出  *
*********************************************
6
谢谢使用,88
Press any key to continue
程序中的编码,数据,译码等数据都是保存在指定文件中,对文件流操作可以做点复习。



  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值