大一写的哈夫曼编码程序(今天贴上)



/*
霍夫曼编码
哈夫曼树(Huffman Tree),又叫最优二叉树,指的是对于一组具有确定权值的叶子结点的具有最小带权路径长度的二叉树
1.数据移动时无符号不同于有符号,右移要默认为0
2.文件操作以字节为最小单位。凑足写入,最后多一个字节写上次剩余多少
3.区分叶子节点与内部节点,8个字符的最长路径为7


无符号类型的应用,位操作在有符号时候会带符号操作,当系统使用文本方式打开文件后,会对回车做相应处理。文件读取不正确
移位操作时候注意左右不同。当最后一个单元不能完全保存时,最后用一个来存储最后一次操作的位数
	k<<=32-count;移位至前面,自底向上寻找编码,但从上到下使用


*/#include<stdio.h>
#include<stdlib.h>
#include<conio.h>
#include<string.h>
#define N 511
#define M 256
typedef struct HTree
{
	unsigned char ch;
	int parent,lchild,rchild;
	unsigned int code;
	int codenum;
	double weight;
}Tree;
Tree tree[N]={0};
void encode();
void hufftree();
void getcode();
void crackcode();
void printcode();
void translatecode(unsigned char *rdtemp,int filesize);
int main()
{
	char ch[3];
	while(1)
	{
		system("cls");
		printf("             -----------------------哈夫曼编码解码---------------------\n\n");
		printf(" 						BY:XSY\n\n\n\n");
		printf(" 				1.哈夫曼编码\n");
		printf(" 				2.哈夫曼解码\n");
		printf(" 				3.打印各个字符的哈夫曼编码\n				0.EXIT\n\n");
		printf("注:编码文件为test.txt,解码文件名为Htest.txt与源程序放在同一目录\n\n\n			");
		gets(ch);
		switch(ch[0])
		{
		case '0': return 0;
		case '1':encode();break;
		case '2':crackcode();break;
		case '3':printcode();break;
		}	
	}


	
	
	return 0;
}
void encode()
{
	FILE *fp;
	if((fp=fopen("test.txt","rb"))==NULL)
		exit(0);
	int All_char[M]={0};
	
	int i;
	unsigned char rdtemp[100000];
	i=sizeof(unsigned char);
	long filesize;
	fseek(fp,0,2);
	filesize=ftell(fp);
	rewind(fp);
	fread(rdtemp,filesize,1,fp);
	fclose(fp);							//读入文本
	i=0;
	while(i<filesize)
		All_char[rdtemp[i++]]++;		
	for(i=0;i<M;i++)
	{
		tree[i].ch=i;
		tree[i].parent=-1;
		tree[i].weight=All_char[i]/(double)filesize;
	}	
	for(i=M;i<N;i++)
		tree[i].parent=-1;												//统计字符
	hufftree();															//create哈夫曼编码
	getcode();
																			//译码写入
	translatecode(rdtemp,filesize);
	printf("\n\n	mission successful! press any key to back...\n");
	_getch();
	
	
}
void hufftree()
{
	int i;
	int num1,num2;
	int count;
	double min1,min2;
	int arc;
	arc=M;
	count=0;
	while(arc<N)
	{
		
		for(i=0,min1=min2=1.0;i<arc;i++)
		{
			if(tree[i].parent != -1)
				continue;
			if(tree[i].weight<min2)
			{
				if(tree[i].weight<min1)
				{
					num2=num1;
					num1=i;
					min2=min1;
					min1=tree[i].weight;
				}
				else
				{
					num2=i;
					min2=tree[i].weight;
				}
			}
		}
		tree[arc].lchild=num1;
		tree[arc].rchild=num2;
		tree[arc].weight=min1+min2;
		tree[num1].parent=arc;
		tree[num2].parent=arc;
		arc++;
	}

}
void getcode()
{
	int i,j;
	int codenum;
	int chcount=0;
	while(chcount<M)
	{
		codenum=0;
		i=chcount;
		while(tree[i].parent != -1)
		{
			tree[chcount].code>>=1;
			codenum++;
			j=tree[i].parent;
			if(tree[j].rchild == i)
				tree[chcount].code |=0x80000000;			
			i=j;
		}
		tree[chcount].codenum=codenum;
		chcount++;
	}
/*
	for(i=j=0;i<M;i++)
	{
		j=tree[i].codenum>j?tree[i].codenum:j;
		//printf("%c %d\n",tree[i].ch,tree[i].code);

	}*/

}
void translatecode(unsigned char *rdtemp,int filesize)
{
	FILE *fp;
	int i,j,count;
	unsigned int k,l;
	if((fp=fopen("Htest.txt","wb"))==NULL)
		exit(0);	
	fwrite(tree,sizeof(Tree),N,fp);
	for(i=k=count=0;i<filesize;i++)
	{
		l=tree[rdtemp[i]].code;
		for(j=0;j<tree[rdtemp[i]].codenum;j++,count++)
		{			
			if(count == 32)
			{				
				fwrite(&k,sizeof(int),1,fp);
				count=k=0;
			}
			k<<=1;
			if((l&0x80000000) == 0x80000000)
				k|=1;
			l<<=1;
		}
	}
	k<<=32-count;
	if(count)
		fwrite(&k,sizeof(int),1,fp);
	fwrite(&count,sizeof(int),1,fp);
	fclose(fp);
}
void crackcode()
{
	int i,j,k;
	unsigned int oparrey[500]={0};
	FILE *fp;
	if((fp=fopen("Htest.txt","r+b"))==NULL)
		exit(0);
	ftell(fp);
	fread(tree,sizeof(Tree),N,fp);
	long filesize1,filesize2,filesize;
	filesize1=ftell(fp);	
	fseek(fp,0,2);
	filesize2=ftell(fp);	
	filesize=filesize2-filesize1;
	filesize/=4;
	fseek(fp,filesize1,0);
	fread(oparrey,sizeof(int),filesize,fp);
	fclose(fp);
	for(i=0,k=N-1;i<filesize-2;i++)
	{
		for(j=0;j<32;j++)
		{
			if((oparrey[i]&0x80000000) == 0x80000000)
				k=tree[k].rchild;
			else
				k=tree[k].lchild;
			if(tree[k].ch)
			{
				putchar(tree[k].ch);
				k=N-1;
			}//字符处理
			oparrey[i]<<=1;
		}
	}
	for(j=0;j<(signed)oparrey[filesize-1];j++)
		{
			if((oparrey[i]&0x80000000) == 0x80000000)
				k=tree[k].rchild;
			else
				k=tree[k].lchild;
			if(tree[k].ch)
			{
				putchar(tree[k].ch);
				k=N-1;
			}//字符处理
			oparrey[i]<<=1;
		}
		printf("\n\n	mission successful! press any key to back...\n");
	_getch();
}
void printcode()
{
	unsigned int k;
	for(int i=0;i<M;i++)
		{
			k=tree[i].code;
			printf("%c\t",tree[i].ch);
			for(int j=0;j<tree[i].codenum;j++)
			{
				if((k&0x80000000) == 0x80000000)
					putchar('1');
				else
					putchar('0');
				k<<=1;
			}
			putchar('\n');
		}
		printf("\n\n	mission successful! press any key to back...\n");
	_getch();
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值