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);  //輸出譯碼後字符串
	}

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