哈夫曼编码和译码的实现

哈夫曼编码和译码的实现

#include 
#include 
#include 
#include 

using namespace std;

/*哈夫曼树的应用----哈夫曼编码*/

//哈夫曼树的结点结构
typedef struct HuffmanTree{
	int weight;
	int parent,lchild,rchild; //编码及译码需要这三个信息 
}HTNode,*HTree; 

typedef char** HuffmanCode;     //二级指针,存放指针 
const int LeafNum=8;    		//叶子结点个数 

void HuffmanCoding(HTree& HT,int *w,int n);        		    //构造哈夫曼树的过程 
void select(HTree HT,int t,int&s1,int&s2);					//选择F中权值最小的两个结点 
void HuffmanCoded(HTree& HT,HuffmanCode& HC,int n,char* p); //求解哈夫曼编码 
void translate(HTree& HT,int a,int* b,int BiLen,char* p)//译码

void HuffmanCoding(HTree& HT,int *w,int n)
{
	int s1,s2;
	int m;
	int i=0;
	if(n<=1)  return;
	m=2*n-1;  	//哈夫曼树的结点个数
	HT=(HTNode*)malloc(sizeof(HTNode)*(m)); 
	HTree p=HT;
	for(i=0;i<n;++i,++p,++w)
	{
		*(p)={*w,-1,-1,-1};  //初始化叶子结点完成 
	}
	for(;i<m;++i,++p)
	{
		*(p)={-1,-1,-1,-1};   //除叶子结点外的结点初始化完成 
	}
	cout<<"初始化后:"<<endl;
	cout<<"双亲"<<'\t'<<"左孩子"<<'\t'<<"右孩子"<<'\t'<<"权值"<<endl;
	for(int i=0;i<m;i++)
	{
		cout<<HT[i].parent<<'\t'<<HT[i].lchild<<'\t'<<HT[i].rchild<<'\t'<<HT[i].weight<<endl;
	}
	for(i=n;i<m;++i)
	{
		//在HT[1..i-1]中选择parent为0且weight最小的两个结点,其序号分别为s1和s2
		select(HT,i,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;
	}
	cout<<'\n'<<"完成后:"<<endl;
	cout<<"双亲"<<'\t'<<"左孩子"<<'\t'<<"右孩子"<<'\t'<<"权值"<<endl;
	for(int i=0;i<m;i++)
	{
		cout<<HT[i].parent<<'\t'<<HT[i].lchild<<'\t'<<HT[i].rchild<<'\t'<<HT[i].weight<<endl;
	}
	cout<<endl;
}

void HuffmanCoded(HTree& HT,HuffmanCode& HC,int n,char* p)
{
	int c,start,f;
	char* cd;
	HC=(HuffmanCode)malloc(sizeof(char*)*(n));   //存放字符型编码的指针
	cd=(char*)malloc((n)*sizeof(char));  		 //存放字符型编码 
	cd[n-1]='\0';   
	for(int i=0;i<n;++i)
	{
		start=n-1;
		for(c=i,f=HT[i].parent;f!=-1;c=f,f=HT[f].parent)
		{
			//从下往上找的编码逆着放,即为从上往下的顺序 
			if(HT[f].lchild==c)  cd[--start]='0';
			else cd[--start]='1';
		}
		HC[i]=(char*)malloc(sizeof(char));  //HC[i]即为指针 
		strcpy(HC[i],&cd[start]);
	}
	cout<<"哈夫曼编码为:"<<endl;
	for(int i=0;i<8;i++)
	{
		cout<<p[i]<<'\t';
	}
	cout<<endl; 
	for(int i=0;i<n;i++)
	{
		cout<<HC[i]<<'\t';
	}
	cout<<endl;
}

void translate(HTree& HT,int a,int* b,int BiLen,char* p)
{
	int n=2*a-2;
	int i=0;
	cout<<'\n'<<"传递的二进制消息为:"<<endl;
	for(int i=0;i<BiLen;i++)
	{
		cout<<b[i];
	}
	cout<<'\n';
	cout<<'\n'<<"对二进制编码译码后,其内容为:"<<endl;
	for(;;)
	{
		//根据二进制编码找叶子结点 
		if(b[i]==0&&HT[n].lchild!=-1) 
		{
			n=HT[n].lchild;
			i++;
		}
		else if(b[i]==1&&HT[n].rchild!=-1)
		{
			n=HT[n].rchild;
			i++;
		}
		else
		{
			cout<<p[n];
			n=2*a-2;
			if(i>BiLen-1) 
			{
				break;	
			}
		}
	}
}

void select(HTree HT,int t,int&s1,int&s2)
{
	//在HT[1...t]中选择parent不为0且权值最小的两个结点,其序号分别为s1和s2  
	int i,m,n;
	m=n=10000;   
	for(i=0;i<t;i++)
	{
		if(HT[i].parent==-1&&(HT[i].weight<m||HT[i].weight<n))
		{
			if(m<n)
			{
				n=HT[i].weight;
				s2=i;
			}
			else
		    {
				m=HT[i].weight;
				s1=i;
			}
		}
	}
	if(s1>s2) //s1放较小的序号
	{
		i=s1;
		s1=s2;
		s2=i;
	}
}

int main()
{
	int  w[LeafNum]={5,29,7,8,14,23,3,11};             //叶子结点权值 
	char p[LeafNum]={'h','e','c','d','l','b','o','h'}; //叶子结点对应的字符 
	int BiMessage[]={0,1,1,0,1,0,1,1,0,1,1,0,0,1,1,1}; //传递的二进制信息 
	int BiLen=sizeof(BiMessage)/sizeof(int);
	HTree HT;
	HuffmanCode HC;
	HuffmanCoding(HT,w,LeafNum);
	HuffmanCoded(HT,HC,LeafNum,p);
	translate(HT,LeafNum,BiMessage,BiLen,p);
	return 0;
}

运行结果:
哈夫曼编码和译码的实现_第1张图片

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