赫夫曼树编码及解码

#include<stdio.h>
#include<stdlib.h>
typedef struct
{	
	char content;
	int weight;
	int parent,lchild,rchild;
}HTNode,*HuffmanTree;//动态分配数组存储赫夫曼树
typedef int **HuffmanCode;//动态分配数组存储赫夫曼编码表
void HuffmanCoding(HuffmanTree &HT,HuffmanCode &HC,char *ch,int *w,int n);//赫夫曼编码
void Select(HuffmanTree HT,int x,int &s1,int &s2);//选择权值最小的两个数
void Intcpy(int *p,int *q);//复制编码
void DecodeHuffman(HuffmanTree HT,int n);//解译赫夫曼编码
void main()
{	
	char x,ch[]={'A','B','C','D','E','F','G','H'};//需要编码的字符
	int w[]={5,29,7,8,14,23,3,11},n=8;//各字符对应的权值
	HuffmanTree HT;
	HuffmanCode HC;
	HuffmanCoding(HT,HC,ch,w,n);
	while(1)
	{	
		DecodeHuffman(HT,n);
		printf("是否想继续解码?(Y/N):");
		x=getchar();
		getchar();//消去回车符,避免被DecodeHuffman中的gets()使用而出错
		if(x!='Y'&&x!='y')
			break;
	}

	for (int i=0;i<n+1;i++)
		free(HC[i]);
	free(HC);
	free(HT);
}
void Select(HuffmanTree HT,int x,int &s1,int &s2)
{	
	HTNode p;
	int i,j=2,k;
	while(j--)
	{	
		for(i=1;HT[i].parent;i++);
		for(k=i,p=HT[i];i<=x;i++)
			if(HT[i].parent==0&&HT[i].weight<p.weight)
			{	
				p=HT[i];
				k=i;
			}
		HT[k].parent=1;
		if(j==1)
			s1=k;
		else
			s2=k;
	}
}
void Intcpy(int *p,int *q)
{	
	for(;*p!=-1;p++,q++)
		*q=*p;
	*q=-1;
}
void HuffmanCoding(HuffmanTree &HT,HuffmanCode &HC,char *ch,int *w,int n)
{	//w存放权值,构造赫夫曼树,并求出n个字符的赫夫曼编码
	int *cd,s1,s2,m,i,start,c,f,temp;
	if(n<=1)
		return;
	m=2*n-1;
	HT=(HuffmanTree)malloc((m+1)*sizeof(HTNode));//不用0号
	for(HT,i=1;i<=n;++i,++w,++ch)
	{	
		HT[i].weight=*w;
		HT[i].content=*ch;
		HT[i].parent=HT[i].lchild=HT[i].rchild=0;
	}
	for(;i<=m;++i)
		HT[i].weight=HT[i].parent=HT[i].lchild=HT[i].rchild=0;
	for(i=n+1;i<=m;++i)
	{	//构造赫夫曼树
		//在HT[1...i-1]选择parent为0且weight最小的两个节点,其序号分别为s1和s2
		Select(HT,i-1,s1,s2);
		if(s1>s2)
		{	
			temp=s1;
			s1=s2;
			s2=temp;
		}
		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;
	}
	////-----------从叶子到根逆向求每个字符的赫夫曼编码---------------
	HC=(HuffmanCode)malloc((n+1)*sizeof(int *));
	cd=(int*)malloc(n*sizeof(int));
	cd[n-1]=-1;
	printf("Huffman编码结果为:\n");
	for(i=1;i<=n;++i)
	{	
		start=n-1;
		for(c=i,f=HT[i].parent;f!=0;c=f,f=HT[f].parent)
			if(HT[f].lchild==c)
				cd[--start]=0;
			else
				cd[--start]=1;
		HC[i]=(int *)malloc((n-start)*sizeof(int));
		Intcpy(&cd[start],HC[i]);            
		printf("%c---",HT[i].content);
		for(;*HC[i]!=-1;HC[i]++)
			printf("%d",*HC[i]);
		printf("\n");
	}

	free(cd);
}
void DecodeHuffman(HuffmanTree HT,int n)
{//根据字符'0'或'1'来确定找左右孩子,直至叶子结点
	char str[100];
	int i,m=2*n-1;
	HTNode p;
	printf("请输入你想解译的编码:\n");
	gets(str);
	printf("解码结果为:");
	for(i=0,p=HT[m];str[i];i++)
	{	
		if(str[i]=='0')
		{	
			p=HT[p.lchild];
			if(p.lchild==0&&p.rchild==0)
			{	
				printf("%c",p.content);
				p=HT[m];
			}
		}
		else
		{	
			p=HT[p.rchild];
			if(p.lchild==0&&p.rchild==0)
			{	
				printf("%c",p.content);
				p=HT[m];
			}
		}
	}
	printf("\n");
}

你可能感兴趣的:(Algorithm,数据结构)