哈弗曼编码和译码

//此代码是数据结构的原始模板,可以刚接触或考研时借鉴下,不适于刷题
#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;
}


		
	

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值