[置顶] 哈弗曼编码和译码

//此代码是数据结构的原始模板,可以刚接触或考研时借鉴下,不适于刷题
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<windows.h>
int s1,s2,nlayer=0,S,T;
FILE *fp1,*fp2,*fp3;
char english1[10000];
typedef struct node
{
	int weight;
	int parent;
	int lchild;
	int rchild;
	char ch;
}tree,*bitree;
void selet(tree ht[],int x)
{
	int i,min1='0x3f',min2='0x3f';
	for(i=1;i<=x;i++)
	{
       if(min1>ht[i].weight&&ht[i].parent==0)
	   {
	     min1=ht[i].weight;
	   }
	}
   for(i=1;i<=x;i++)
	{
       if(min1==ht[i].weight&&ht[i].parent==0)
	   {
	     s1=i;
		 ht[i].parent=-1;
		 break;
	   }
	}
	for(i=1;i<=x;i++)
	{
       if(min2>ht[i].weight&&ht[i].parent==0)
	   {
	     min2=ht[i].weight;
	   }
	}
		for(i=1;i<=x;i++)
	{
       if(min2==ht[i].weight&&ht[i].parent==0)
	   {
	     s2=i;
		 break;
	   }
	}
	ht[s1].parent=0;
	if(min1==min2)
	{
		int r=s1;
		s1=s2;
		s2=r;
	}
	
}
bitree crthuffmantree(tree ht[],int w[],int n)//构造哈弗曼树
{
	for(int i=1;i<=n;i++)
	{
		ht[i].weight=w[i];//表示权值
		ht[i].parent=0;
		ht[i].lchild=0;
		ht[i].rchild=0;
	}
	int m=2*n-1;//表示有哈弗曼树有n个结点
	T=S=m;
	for(i=n+1;i<=m;i++)
	{
		ht[i].weight=0;
	    ht[i].parent=0;
		ht[i].lchild=0;
		ht[i].rchild=0;
	}//对不为叶结点的子树初始化
	for(i=n+1;i<=m;i++)
	{
		selet(ht,i-1);//在前n个里面选两个权值最小的子树
	    ht[i].weight=ht[s1].weight+ht[s2].weight;
	    ht[s1].parent=i;
		ht[s2].parent=i;
		ht[i].lchild=s1;
		ht[i].rchild=s2;
	}
	return ht;
}
typedef char *huffmancode[10000];
 bitree crthuffmancode(tree ht[],huffmancode hc,int n,char is[],char english[],int w[])//哈弗曼编码
{
	char *cd,sh,sh1[10000];
	int start,c,p,e;
	cd=(char*)malloc(n*sizeof(char));
	cd[n-1]='\0';
	for(int i=1;i<=n;i++)
	{
		start=n-1;
		c=i;
		p=ht[i].parent;
		if(p==0)
		{
		hc[i]=(char*)malloc((n-start)*sizeof(char));
		strcpy(hc[i],"1");
		}
		else
		{
		while(p!=0)
		{
			--start;
			if(ht[p].lchild==c)
				cd[start]='0';
			else
				cd[start]='1';
			c=p;
			p=ht[p].parent;
		}
		hc[i]=(char*)malloc((n-start)*sizeof(char));
		strcpy(hc[i],&cd[start]);
		}
	}
	for(i=1;i<=n;i++)//在终端显示各字符的编码
	ht[i].ch=is[i];
	printf("--------------------------------------------------------------------------------");
	int choice;
	printf("功能1:显示各字符编码\n");
	printf("功能2:在D盘文件CodeFile3中生成各字符的权值\n");
	printf("功能3:在D盘文件CodeFile1中生成文段代码\n");
	printf("请选择功能:");
	while(scanf("%d",&choice)!=EOF)
	{
	if(choice==1)
	{
	for(i=1;i<=n;i++)//在终端显示各字符的编码
	printf("字符%c的编码:%s\n",is[i],hc[i]);
	}
	else if(choice==2)
	{
	fp3=fopen("d:\\CodeFile3.txt","w");//在文件CodeFile3中生成各字符的权值
	if(fp3==NULL)
	{
	printf("cannot open filel.txt\n");
			exit(0);
	}
    char t1[10];
	strcpy(t1,"VER");
	fputs(t1,fp3);
	fputc(' ',fp3);
	char t2[10];
	strcpy(t2,"WEIGHT");
	fputs(t2,fp3);
	fputc(' ',fp3);
	char t3[10];
	strcpy(t3,"LCHILD");
	fputs(t3,fp3);
	fputc(' ',fp3);
	char t4[10];
	strcpy(t4,"RCHILD");
	fputs(t4,fp3);
	fputc(' ',fp3);
	char t5[10];
	strcpy(t5,"PARENT");
	fputs(t5,fp3);
	fputc('\n',fp3);
	for(i=1;i<=n;i++)
	fprintf(fp3,"%c  :  %d      %d      %d      %d\n",ht[i].ch,w[i],ht[i].lchild,ht[i].rchild,ht[i].parent);
	fclose(fp3);
	}
	else if(choice==3)
	{
    for(e=0;e<strlen(english);e++)
	{
		for(i=1;i<=n;i++)
		{
			if(english[e]==is[i])
            strcat(english1,hc[i]);
		}
	}
    fp1=fopen("d:\\CodeFile1.txt","w");//在文件CodeFile1中生成文段代码
	if(fp1==NULL)
	{
	printf("cannot open filel.txt\n");
			exit(0);
	}
	fputs(english1,fp1);
	fclose(fp1);
	}
	else
	{
	 break;
	}
	printf("请选择功能:");
	}
	free(cd);
	return ht;
}
void decode(tree ht[],char is[],int n)//哈弗曼译码
{	
	char b[10000];
	b[0]='\0';	
	printf("请输入您的文段编码:");
    while(scanf("%s",&b[1])!=EOF)
	{
	if(n==1)
		printf("%c\n",ht[n].ch);
	else
	{
	int i=1,j=1;
	i=S;
	printf("您的文段译码输出为:");
	printf("\n________________________________________________________________________________\n");
	while(b[j]!='\0')
	{
		if(b[j]=='0')
		i=ht[i].lchild;
		else if(b[j]=='1')
		i=ht[i].rchild;
		if(ht[i].lchild==0&&ht[i].rchild==0)
		{
			printf("%c",ht[i].ch);
			i=S;
		}
		j++;
	}
	printf("\n________________________________________________________________________________\n");
	printf("请输入您的文段编码:");
	}
	}
}
void printree(tree ht[],int nlayer,int kans)//在终端和文件CodeFile2中打印哈弗曼树
{
	if(ht[kans].weight==0)
	return ;
	printree(ht,nlayer+1,ht[kans].rchild);
	for(int i=0;i<nlayer;i++)
	{
    printf("  ");
    fputc(' ',fp2);
	}
	printf("%d\n",ht[kans].weight);
	fprintf(fp2,"%d",ht[kans].weight);
    fputc('\n',fp2);
	printree(ht,nlayer+1,ht[kans].lchild);
}
int main()
{
	int time1=110,time2=500;
	printf("|***********************");
	Sleep(time1);
	printf("【");
	Sleep(time1);
	printf("欢");
	Sleep(time1);
    printf("迎");
	Sleep(time1);
	printf("进");
	Sleep(time1);
	printf("入");
	Sleep(time1);	
	printf("哈");
	Sleep(time1);
	printf("弗");
	Sleep(time1);
	printf("曼");
	Sleep(time1);
	printf("编");
	Sleep(time1);
	printf("码");
	Sleep(time1);
	printf("和");
	Sleep(time1);
	printf("译");
	Sleep(time1);
	printf("码");
	Sleep(time1);
	printf("系");
	Sleep(time1);
	printf("统");
	Sleep(time1);
	printf("】");
	Sleep(time1);
	printf("***********************|");
	Sleep(time1);
	char english[10000],is[10000];
	huffmancode Huffmancode;
	printf("请输入一段字符串可利用哈弗曼树原理求出字符串中各字符的哈弗曼编码:\n");
	gets(english);
	int len=strlen(english);
	int i,j,ajj[10000],kans;
	ajj[0]=0;
	ajj[1]=1;
	is[1]=english[0];
	int ans=1;
	for(i=1;i<len;i++)
	{
		for(j=1;j<=ans;j++)
		{
		if(english[i]==is[j])
		{
			ajj[j]++;
			break;
		}
		}
		if(j==ans+1)
		{
			is[ans+1]=english[i];
			ajj[ans+1]=1;
			ans++;//表示有多少个不同的字母
		}
	}
	tree hufu[400];
	bitree ht1,ht2;
	hufu[0].weight=0;
	hufu[0].parent=0;
	hufu[0].lchild=0;
	hufu[0].rchild=0;
	ht1=crthuffmantree(hufu,ajj,ans);//构造哈弗曼树
	kans=T;
	ht2=crthuffmancode(ht1,Huffmancode,ans,is,english,ajj);//哈弗曼编码
	fp2=fopen("d:\\CodeFile2.txt","w");	
	if(fp2==NULL)
	{
	printf("cannot open file2.txt\n");
	exit(0);
	}
	Sleep(time2);
	printf("-----------------\n");
	printf("打印输出哈弗曼树:\n");
	printf("-----------------\n");
	printree(ht2,nlayer,kans);//打印哈弗曼树
    printf("-----------------\n");
	fclose(fp2);
	decode(ht2,is,ans);//哈弗曼译码
	return 0;
}


		
	

你可能感兴趣的:(哈弗曼编码和译码)