Huffman编码问题

#include<stdio.h>        
#include<string.h>
#include<stdlib.h>
#define n 100
#define m 2*n-1
typedef struct {
	char ch;
	char bits[9];
	int len;
}CodeNode;
typedef CodeNode HuffmanCode[n+1];
typedef struct {
	int weight;               //权值
	int lchild,rchild,parent; //左右孩子及双亲指针
}HTNode;
typedef HTNode HuffmanTree[m+1];//0号单元不可用
int num;

void select(HuffmanTree T,int k,int &s1,int &s2)
{//在HT[1..k]中选择parent为0且权值最小的两个根结点,
	//其序号分别为s1和s2
	int i,j;int min1=101;
	for(i=1;i<=k;i++)
		if(T[i].weight<min1 && T[i].parent==0)
		{
			j=i;min1=T[i].weight;
		}
		s1=j;min1=32767;
		for(i=1;i<=k;i++)
			if(T[i].weight<min1 && T[i].parent==0 && i!=s1)
			{
				j=i;min1=T[i].weight;
			}
			s2=j;
}
int jsq(char *s,int cnt[],char str[])
{//统计字符串中各种字母的个数以及字符的种类
	char *p;
	int i,j,k;
	int temp[27];
	for(i=1;i<=26;i++)
		temp[i]=0;
	for(p=s;*p!='\0';p++)
	{//统计各种字符的个数
		if(*p>='A' && *p<='z'){
			k=*p-64;
			temp[k]++;
		}
	}
	j=0;
	for(i=1,j=0;i<=26;i++)  //统计有多少种字符
		if(temp[i]!=0){
			j++;
			str[j]=i+64;  //送对应字母到数组中
			cnt[j]=temp[i];//存入对应字母的权值
		}
		return j;
}
void ChuffmanTree(HuffmanTree HT,HuffmanCode HC,int cnt[],char str[])
{//构造赫夫曼树HT
	int i,s1,s2;
	for(i=1;i<=2*num-1;i++)  //初始化HT
	{ HT[i].lchild=0;HT[i].rchild=0;
      HT[i].parent=0;HT[i].weight=0;
	}
	for(i=1;i<=num;i++)   //输入num个叶结点的权值
		HT[i].weight=cnt[i];
	for(i=num+1;i<=2*num-1;i++)
	{  //在HT[1..-1]中选择parent为0且权值最小的两个根结点,
		//其序号分别为s1和s2);
		select(HT,i-1,s1,s2);
		HT[s1].parent=i; HT[s2].parent=i;
		HT[i].lchild=s1; HT[i].rchild=s2;
		HT[i].weight=HT[s1].weight+HT[s2].weight;
	}
	for(i=0;i<=num;i++)   //输入字符集中的字符
		HC[i].ch=str[i];
	i=1;while(i<=num)
		printf("字符%c,次数为:%d\n",HC[i].ch,cnt[i++]);
}
	void HuffmanEncoding(HuffmanTree HT, HuffmanCode HC)
	{//根据赫夫曼树HT求赫夫曼树编码HC
		int c,p,i;  //c和p分别指示T中孩子和双亲的位置
		char cd[n];  //临时存放编码串
		int start;   //指示编码在cd中起始位置
		cd[num]='\0';  //最后一位放上串结束符
		for(i=1;i<=num;i++)
		{
			start=num;		//初始位置
			c=i;
			while((p=HT[c].parent)>0)   //直至上溯到HT[c]及树根为止
			{//若T[c]是T[p]的左孩子,则生成代码1
				cd[--start]=(HT[p].lchild==c)?'0':'1';
				c=p;
			}//end or while
			strcpy(HC[i].bits,&cd[start]);
			HC[i].len=num-start;
		}//end or for
	}

	void coding(HuffmanCode HC,char *str)
	{//对str所代表的字符串进行编码,并写入文件
		int i,j;
		FILE *fp;
		fp=fopen("codefile.txt","w");
		while(*str){
			for(i=1;i<=num;i++)
				if(HC[i].ch==*str){
					for(j=0;j<HC[i].len;j++)
						fputc(HC[i].bits[j],fp);
					break;
				}
				str++;
		}
		fclose(fp);
	}
	
	char *decode(HuffmanCode HC)
	{//代码文件codefile.txt的译码
		FILE *fp;
		char str[254];   //假设原文件不超过254个字符
		char *p;
		static char cd[n+1];
		int i,j,k=0,cjs;
		fp=fopen("codefile.txt","r");
		while(!feof(fp))
		{
			cjs=0;
			for(i=0;i<num && cjs==0 && !feof(fp);i++)
			{
				cd[i]=' ';cd[i+1]='\0';
				cd[i]=fgetc(fp);
				for(j=1;j<=num;j++)
					if(strcmp(HC[j].bits,cd)==0)
					{
						str[k]=HC[j].ch;k++;
						cjs=1;break;
					}
			}
		}
		str[k]='\0';p=str;
		return p;
	}
	
	void main()
	{
		char st[254],*s,str[27];
		int cn[27];
		HuffmanTree HT;
		HuffmanCode HC;
		printf("输入需要编码的字符串(假设均为大写字母):\n");
		gets(st);
		num=jsq(st,cn,str);          //统计字符的种类及各类字符出现的频率
		ChuffmanTree(HT,HC,cn,str);  //建立赫夫曼树   
		HuffmanEncoding (HT,HC);    //生成赫夫曼树
		coding(HC,st);              //建立电文赫夫曼编码文件
		s=decode(HC);  //读编码文件译码
		printf("译码后的字符串:\n"); 
		printf("%s\n",st);  //输出译码后字符串
	}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章