霍夫曼树编码与译码

博客围绕霍夫曼树展开,虽未给出具体内容,但可知核心为霍夫曼树,它是信息技术领域算法范畴的重要概念。
#include<iostream>
#include<stdlib.h>
#include<cstring>
using namespace std;
typedef struct hftree{
	int might;
	int parent,lch,rch;
	char data; 
}*tree,node;
typedef char** treecode;
int length;//字符串长度; 
void chushi(tree &hf,int n)//初始话 
{
	hf=new node[2*n];
	for(int i=1;i<=2*n-1;i++)
	{
		hf[i].data='\0';
		hf[i].might=0;
		hf[i].lch=0;
		hf[i].rch=0;
		hf[i].parent=0;
	}
} 
void select(tree T,int n,int &s1,int &s2)//找出权值最小的两个; 
{
    int k,m;
	k=m=1000000; 
		for(int j=1;j<=n;j++)
		{
			if(m>T[j].might&&T[j].parent==0)
			{
				m=T[j].might;
				s1=j;			
			}			  
        }               		
		for(int i=1;i<=n;i++)
		{   
			if(i!=s1&&k>T[i].might&&T[i].parent==0)
			{
				k=T[i].might;
				s2=i;				
			}
		}
} 
void hftree(tree &hf,int n)//创建霍夫曼树 
{
	int s1,s2;
	if(n<=1) return;
	int m=2*n-1; 
	for(int i=n+1;i<=m;++i)
	{
		select(hf,i-1,s1,s2);
		hf[s1].parent=i;
		hf[s2].parent=i;
		if(s1<=s2){
		    hf[i].lch=s1;
		    hf[i].rch=s2;
		}
		else{
			hf[i].lch=s2;
		    hf[i].rch=s1;
		}				
		hf[i].might=hf[s1].might+hf[s2].might;				
	}	
}
void codetree(tree hf,treecode &hc,int n)//获取字符的编码值  
{ 	
    int m,p;  		
	hc=new char*[n+1]; //指针数组; 	
    char *cd=new char[n];	//存放编码	   
    cd[n-1]='\0';		
    for(int i=1;i<=n;i++)
    {
    	int start=n-1;
    	m=i;
		p=hf[i].parent;
    	while(p!=0)
    	{
    		--start;
    		if(hf[p].lch==m)
    		{
    			cd[start]='0';
			}
			else
			    cd[start]='1';
			m=p;
		    p=hf[p].parent;			    
		}
		hc[i]=new char[n-start];
    	strcpy(hc[i],&cd[start]);    	   	
	}
	delete []cd;		
}
void input(tree &hf,int &n,char *date)//输入字符串 
{ 
	char *a=date;
	int length_1;
	int num[256]={0};
	int b[256];
	int c[256];
	cout<<"输入字符串:"; 
	getchar();
	gets(a);
	length_1=strlen(a);
	for(int i=0;i<length_1;i++)
	{
		num[(int)a[i]]++;//统计每个字符的权值 
	}
	n=0;
	for(int i=0;i<256;i++)
	{
		if(num[i]!=0)
		{   
		   	b[n]=num[i]; 
		   	c[n]=(char)i; 
			++n;
		}
	}
	hf=new node[2*n];
	for(int i=1;i<=2*n-1;i++)
	{
		hf[i].data='\0';
		hf[i].might=0;
		hf[i].lch=0;
		hf[i].rch=0;
		hf[i].parent=0;
	}
	for(int i=1;i<=n;i++)
	{
		hf[i].might=b[i-1];
		hf[i].data=c[i-1];
	}	
} 
int weizhi(tree hf,char *q,int n) //获取字符在树中的位置 
{
	char *date=q;
    	for(int j=1;j<=n;++j)
    	{
    		if(*date==hf[j].data)
    			return j;
		} 
}
void bianmachar(tree hf,char *q,treecode &result,int n)//对字符串编码 
{
	char *date=q;
	char *cd;
    int m,p;	
	result=new char * [length+1];//存放每个字符的编码值; 	
    cd=new char[n];
    cd[n-1]='\0';   
    for(int i=0;i<length;++i)
    {   
    	m=weizhi(hf,&date[i],n);//获取每个字符在树中的位置 
    	int start=n-1; 
		p=hf[m].parent;
    	while(p!=0)
    	{
    		--start;
    		if(hf[p].lch==m)
    		{
    			cd[start]='0';
			}
			else
			    cd[start]='1';
			m=p;
		    p=hf[p].parent;			    
		}		
		result[i+1]=new char[n-start];
		strcpy(result[i+1],&cd[start]); 			   	   	
	}
	delete cd;		
}	
void chu(tree hf,treecode hc,treecode result,int n)//输出编码 
{
	int m=2*n-1;
	cout<<"每个字符在树中的位置"<<endl; 
	for(int i=1;i<=m;i++)
	{
		cout<<i<<" "<<hf[i].data<<" "<<hf[i].might<<" "<<hf[i].parent<<" "<<hf[i].lch<<" "<<hf[i].rch<<endl;
	}
	cout<<"每个字符的编码"<<endl; 
	for(int i=1;i<=n;i++)
	{
		cout<<hf[i].data<<" "<<hc[i]<<endl;	
	} 
	cout<<"对字符串的编码:";
	for(int j=1;j<=length;j++)
	{
		cout<<result[j];
	}
}
void input_(tree &hf,int &n) //输入每个字符和对应的权值
{
	cout<<"输入字符和对应的权值"<<endl; 
	for(int i=1;i<=n;i++)
	{
		cin>>hf[i].data;
		cin>>hf[i].might;
	}	
} 
void Decodehf(tree hf,char *m,int n)//译码 
{
	char*date=m;//编码字符串
	int LL=strlen(date);//编码字符串长度  
	char data[100];//解码字符串; 
	int p=2*n-1;//获取根节点的位置; 
	int j=0;//头指针 
	for(int i=0;i<length;i++)
	{										
			if(date[i]=='0')
	 		p=hf[p].lch;
			else if(date[i]=='1')
			p=hf[p].rch;				
			if(hf[p].lch==0&&hf[p].rch==0)
			{			
				data[j]=hf[p].data;
				p=2*n-1;
				++j;			
			} 		
}
	cout<<"对应编码:"; 
	for(int k=0;k<j;k++)
	{
		cout<<data[k];
	}
	cout<<endl;
 } 
 void Xmb()//界面 
{	cout<<"\t\t\t------------------------------------------"<<endl;
 	cout<<"\t\t\t|************霍夫曼编码译码**************|"<<endl;
 	cout<<"\t\t\t|----------------------------------------|"<<endl;
 	cout<<"\t\t\t|********1.对字符串进行编码译码**********|"<<endl; 
	cout<<"\t\t\t|----------------------------------------|"<<endl;
 	cout<<"\t\t\t|********2.输入字符的权值编码译码********|"<<endl;
 	cout<<"\t\t\t------------------------------------------"<<endl;
}
int main()
{
	char a;
	char date_1[100];//输入字符串统计权值 
	char date_2[100];//需要要编码的字符串 
	char date_3[100];//存储译码的字符串
	tree hf; //hfm树 
	treecode hc;//存储每个字符的译码 
	treecode result;//存放译码的字符串 
	int n;//拥有权值的字符个数 	
	while(1)
	{	
		Xmb();
		cout<<"输入相应命令:"; 
		cin>>a;
		switch(a)
		{
			case '1':	
					input(hf,n,date_1); 
					hftree(hf,n);//创建霍夫曼树 
					codetree(hf,hc,n);//每个字符的编码 
					cout<<"输入需要编码的字符串:";
					gets(date_2);
					length=strlen(date_2);
					bianmachar(hf,date_2,result,n);//字符串的编码 					
					chu(hf,hc,result,n);
					cout<<endl;
					cout<<"输入需要译码的编码:" ; 
					gets(date_3);
					Decodehf(hf,date_3,n);
					break;		
			case '2':			
					cout<<"输入字符个数:";
					cin>>n;
					chushi(hf,n);//对霍夫曼树初始化 
					input_(hf,n);//输入字符和对应的权值 
					hftree(hf,n);
					codetree(hf,hc,n);
					cout<<"输入需要编码的字符串:";
					getchar();
					gets(date_2);
					length=strlen(date_2);
					bianmachar(hf,date_2,result,n);
					chu(hf,hc,result,n);
					cout<<endl;
					cout<<"输入需要译码的编码:" ; 
					gets(date_3);
					Decodehf(hf,date_3,n);
					break;
			case '0':
					exit(0);						
		}	
	}

}

在这里插入图片描述
在这里插入图片描述

数据结构关于二叉树的建立遍历以及应用二叉树进行编解码 实验要求 必做部分 1. 小明会按照前序的方式输入一棵二叉树。例如,输入$ACG##H##D##BE#I##F##的话,代表了下面这棵树: 2. 请分别按照前序、中序、后序输出这棵树。 选做部分 背景 在影视剧中,我们经常会看到二战期间情报人员使用电报哒哒哒地发送信息,发送电报所使用的编码叫做摩尔斯电码(或者叫做摩斯密码)。甚至在现代,SOS仍然是国际通用的求救信号之一,其“三短、三长、三短”同样是摩斯密码的编码方式。 摩斯密码使用若干个“点”和“划”来表示一个字母,字母和字母之间使用短暂的停顿来表示。例如,一种常见的编码方式为: 字母 摩斯密码 字母 摩斯密码 A .- E . B -... F ..-. C -.-. G --. D -.. H .... 实际上,一个摩斯密码本可以使用一棵二叉树来存储: 上图表示,从根节点start开始,遇到一个点(Dot)就访问它的左子树节点,遇到一个划(Dash)就访问它的右子树节点。例如,三个点...代表了S,三个划---代表了O。所以SOS的摩斯密码是... --- ...(中间用空格隔开,表示短暂的停顿)。再比如,爱疯手机有一种来电铃声的节奏为“哇哇哇 哇-哇- 哇哇哇”,这其实表示的是…… 现在,小明想在课上偷偷跟你传纸条,但又不想被其他同学看到内容。因此他跟你约定,每次给你传纸条时都使用摩斯密码来编写。至于密码本,当然不能使用国际通用的,他会在课前告诉你密码本的内容。然而小明发现,每次写纸条、读纸条都不是很方便,所以他想让你做个程序来自动编码/解码你们的摩斯密码。 题目要求 首先,小明输入的那棵二叉树,代表了你们在这堂课上要使用的摩斯密码本。例如,输入$ACG##H##D##BE#I##F##的话,代表了下面这棵树: 第一个字母$是什么并不重要,因为它只是代表了根节点,而根节点在我们的摩斯电码中并不代表一个字符,仅仅代表“start”。 读入密码本后,请记得按照前序、中序、后序输出这棵树。 然后,小明会输入一个数,代表接下来输入的是明文还是摩斯电码。输入0表示接下来他会输入明文,输入1表示接下来输入的是摩斯电码,输入-1程序退出。 1. 如果输入的是0,代表接下来要输入的是明文。程序接受一个字符串,根据字符串中每一个字母输出对应的摩斯电码,用空格隔开。例如如果小明输入“BED”,则程序应该输出“-空格-.空格.-”。如果遇到密码本中没有的字符,则输出“输入有误”。 2. 如果输入的是1,则表示接下来要输入摩斯电码。小明首先会输入一个数字N,代表有几个电码的输入,例如输入4代表之后会输入4个电码(即这个单词有四个字母)。随后输入空格分割的电码,例如, .. . -- -. 程序需要根据摩斯电码解读出明文单词并输出,例如上面的电码表示“CAFE”。如果遇到密码本中没有的编码,则输出“输入有误”。 输入输出样例 必做部分: 请输入二叉树: $ACG##H##D##BE#I##F## 前序遍历:$ACGHDBEIF 中序遍历:GCHAD$EIBF 后序遍历:GHCDAIEFB$ 选做部分: 请选择(0为明文,1为电码,-1退出):0 请输入明文:BED 摩斯电码为:- -. .- 请选择(0为明文,1为电码,-1退出):1 请输入电码个数:4 请输入电码:.. . -- -. 明文为:CAFE 请选择(0为明文,1为电码,-1退出):-1 // 程序结束
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值