⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 huffmantree.cpp

📁 huffmantr
💻 CPP
字号:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define LETTER {'\0',' ','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'}
#define VALUE   {0,186,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}
#define N			27
#define MAXLENGTH	20
typedef struct HTreeNode{
	int	letter;
	int	weight,parent,lchild,rchild;
	}HTNode;//构造huffman树结点的存储结构


void Select(HTNode *Htree,int a,int *m1,int *m2)
{//Htree为一棵待建的huffman树,在Htree[1]----Htree[a]中选择
 //parent为0且weight最小的两个结点,序号分别为*m1,*m2
 int i,sum;
 *m1=1;
 while(Htree[*m1].parent)	//让*m1等于第一个parent为0的结点序号
	(*m1)++;
 *m2=*m1+1;
 while(Htree[*m2].parent)	//让*m2等于第二个parent为0的结点序号
	(*m2)++;
 for(i=*m2+1;i<=a;i++){
  if((!Htree[i].parent)&&(Htree[i].weight<Htree[*m1].weight))
		*m1=i;
  else if((!Htree[i].parent)&&(Htree[i].weight<Htree[*m2].weight))
		*m2=i;
	}//for,实现Htree[*m1].weight和Htree[*m2].weight最小
 if(Htree[*m1].weight>Htree[*m2].weight){
	sum=*m1;
	*m1=*m2;
	*m2=sum;
	}//if,确保Htree[*m1].weight<=Htree[*m2].weight
 }//Select


void HuffmanTreeing(HTNode *Htree,int k)
{//构造huffman树Htree,其叶子结点的权值已初始化
 int i,s1,s2;
 int *x1=&s1;
 int *x2=&s2;
 for(i=k+1;i<=2*k-1;i++){
	Select(Htree,i-1,x1,x2);		//调用Select
	Htree[s1].parent=i;
	Htree[s2].parent=i;
	Htree[i].lchild=s1;
	Htree[i].rchild=s2;
	Htree[i].weight=Htree[s1].weight+Htree[s2].weight;
	}//for,构造非叶子结点
}//HuffmanTreeing


void HuffmanCoding(HTNode *Htree,char **Hcode,int k,int *length)
{//利用已构造好的huffman树求出各个字符的huffman编码Hcode
 char *cd;
 int i,j,f,start;
 cd=(char *)malloc(k*sizeof(char));	//分配编码的工作空间
 if(!cd)
	printf("OVER FLOW!");
 cd[k-1]='\0';						//编码结束符
 for(i=1;i<=k;++i){					//逐个字符求huffman编码
	start=k-1;						//编码结束符位置
	for(j=i,f=Htree[i].parent;f!=0;j=f,f=Htree[f].parent){
		if(Htree[f].lchild==j)
			cd[--start]='0';
		else
			cd[--start]='1';
		}//for,从叶子到根逆向求huffman编码
	Hcode[i]=(char*)malloc((k-start)*sizeof(char));
									//为第i个字符分配空间
	length[i]=k-start;			//将第i个字符编码的长度(含字符串
									//结束符)存到length[i]
	strcpy(Hcode[i],&cd[start]);    //从cd复制编码到HC[i]
	}//for
 free(cd);							//释放工作空间
}//HuffmanCoding


void Letter_switch(HTNode *Htree,char **Hcode,int k,int *length)
{//由用户输入一个字符串,利用huffman树和huffman编码求该字符串
 //的编码
 char *ch;
 int j,i=-1;
 ch=(char *)malloc((MAXLENGTH*sizeof(char)));
									//动态分配储存字符串的数组
 if(!ch)
	printf("OVER FLOW!");
 printf("\n\n\nInput Your String:");
 do{i++;
	if(i%(MAXLENGTH+1)==MAXLENGTH){//空间不够则重新分配
	   ch=(char *)realloc(ch,(strlen(ch)+MAXLENGTH)*sizeof(char));										
	    if(!ch)
			printf("OVER FLOW!");
		}//外层if					     
	ch[i]=getchar();
	}while(*(ch+i)!='\n');//接收用户输入的字符串
 *(ch+i)='\0';			  //字符串结束符
 printf("It's Huffmancode is:");
 for(i=0;ch[i]!='\0';i++){//逐个打印出每个字符的编码
	 for(j=1;j<=k;j++){   //逐个查找huffman树叶子结点
		if(ch[i]==Htree[j].letter){//比较当前结点的letter值和ch[i]
			printf("%s",Hcode[j]);	//打印
			j=k+1;		//打印后利用更改循环变量直接退出内层循环
			}//if,相同则打印出该结点对应的huffman编码
		else if(j==k)	//若不同且已查找到最后一个字符,则报错	
			printf("\n  Your Letter is Wrong!");
		}//内层循环for
	}//外层循环for
 free(ch);				//释放存放字符串的空间
}//Letter_switch


void code_switch(HTNode *Htree,char **Hcode,int k,int *length)
{//用户输入一个“0”,“1”字符串作为huffman编码,利用huffman树和
 //huffman编码对其进行译码
 char *cc,*q,*pa;
 int lmax,lmin,j,i=-1,sum=0,tag;
 cc=(char *)malloc((MAXLENGTH*sizeof(char)));
								//动态分配储存字符串的数组
 if(!cc)
	printf("OVER FLOW!");			
 printf("\n\n\nInput Your Huffmancode:");
 do{i++;
	if(i%(MAXLENGTH+1)==MAXLENGTH){//空间不够则重新分配
	  cc=(char *)realloc(cc,(strlen(cc)+MAXLENGTH)*sizeof(char));
		if(!cc)
			printf("OVER FLOW!");
		}//外层if						
	cc[i]=getchar();
	sum++;			  //sum存输入字符长度(含字符串结束符)
	}while(*(cc+i)!='\n');//接收用户输入的字符串(huffman码)
 *(cc+i)='\0';			  //字符串结束符
 printf("It's Letter Code is:");
 lmin=lmax=length[1];
 for(i=2;i<=k;i++){
	if(length[i]<lmin)
		lmin=length[i];
	if(length[i]>lmax)
		lmax=length[i];
	}//for,求出huffman编码中各个字符编码的最大长度和最小长度
 q=pa=cc;
 tag=1;	    //最外层循环执行标志初始化
 while(tag){//对编码逐个进行译码
		for(i=lmin;i<=lmax;i++){//外层循环以编码长度(含字符串
								//结束符)为循环变量
			if(sum<i)
				break;			//sum为未译编码长度,若剩下的
								//未译编码长度小于当前的编码
								//长度,说明输入编码有错,退
								//出外层循环后报错
			for(j=1;j<=k;j++){	//逐个查找huffman树叶子结点
				if((length[j]==i)&&(strncmp(q,Hcode[j],i-1)==0)){
					//若当前叶子结点对应的huffman编码长度与i相等
					//,且其编码也与当前的q指针所指字符串的前i-1
					//相同,则打印该结点对应的字符
					printf("%c",Htree[j].letter);//打印
					q=q+i-1;		//q指向剩下的未译字符串					
					sum=sum-i+1;	//计算未译编码长度
					j=k+1;			//更改j,为了退出内层循环
					i=lmax+1;		//更改i,为了退出外层循环
					}//if
				}//内层循环for
			continue;//当前编码长度找不到对应字符的huffman编码
					 //,则编码长度加一,再查找一遍
			}//外层循环for
	if(*q=='\0')//若已译完字符串,最外层循环执行标志置“0”		
		tag=0;
	else if(pa==q){//检查q指针是否变化
		printf("\n  Your Code Error!");
		tag=0;
		}//else if,有两种情况执行这段代码:1,未译编码长度sum
		 //小于i,跳出外层循环后,显然pa==q,这时报错;   2,
		 //经过上面两重循环后,q指针未变化,说明找遍所有字符的
		 //huffman编码,仍然没有找到与待译字符串的前几个字符相
		 //匹配的,这时也应由此段代码报错
	else //q指针变化且未到字符串尾,将q重新赋给pa,继续最外层循环
		pa=q;
	}//最外层循环while
 printf("\n");
 free(cc);	 //释放存放字符串(编码)的空间
}//code_switch


void main()
{//利用宏中的数据建造huffman树、完成huffman编码,并将用户输入
 //的字符和编码进行编码与译码
 HTNode *HT,*p;
 int i,j,m,k;
 int *length;
 char letters[N+1]=LETTER;	//利用宏接收字符
 int values[N+1]=VALUE;		//利用宏接收字符的权值
 char **HC;				
 k=N;
 m = 2 * k - 1;
 HT=(HTNode *)malloc((m+1)*sizeof(HTNode));
					//分配指向huffman树的指针空间,0号单元未用
 if(!HT)
	printf("OVER FLOW!");									
 for(p=HT,i=0;i<=k;++i,++p){//初始化叶子结点
	(*p).letter=letters[i];
	(*p).weight=values[i];
	(*p).parent=0;
	(*p).lchild=0;
	(*p).rchild=0;
	}//for
 for(;i<=m;++i,++p){//初始化非叶子结点
	(*p).letter='\0';
	(*p).weight=0;
	(*p).parent=0;
	(*p).lchild=0;
	(*p).rchild=0;
	}//for
 HC=(char **)malloc((k+1)*sizeof(char *));
								//分配k个字符编码的头指针向量
 if(!HC)
	printf("OVER FLOW!");
 length=(int *)malloc((k+1)*sizeof(int));
							//分配储存k个字符编码长度的整型数组
 if(!length)
	printf("OVER FLOW!");
 HuffmanTreeing(HT,k);			//调用HuffmanTreeing
 HuffmanCoding(HT,HC,k,length);	//调用HuffmanCoding
 printf("Every Letter's Huffmancode are:");
 for(i=1;i<=k;i++){//打印出每个字符的huffman编码
	if((i-1)%3==0)
		printf("\n");
	printf("%c:%s",HT[i].letter,HC[i]);//打印
	for(j=1;j<=15-length[i];j++)    //为使输出上下对齐
		printf(" ");
	}//for
 Letter_switch(HT,HC,k,length);		//调用Letter_switch
 code_switch(HT,HC,k,length);		//调用code_switch
 free(HC);		//释放空间
 free(HT);		//释放空间
 free(length);	//释放空间
}//main	

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -