哈夫曼树的搭建

哈夫曼树的搭建
  1. 设计哈夫曼树的结点结构,因为我们需要求解从根到叶子结点的编码及从叶子结点到根结点的译码,所以结点结构包含parent,lchild,rchild,weight。
  2. 我们知道哈夫曼树的总结点数N=2*n-1;则在这里可以采用结构体数组来存储哈夫曼树的所有结点,数组大小为N,下标[0,n-1]存储叶子结点的信息(n个格子),[n,N-1]存储组合后的结点的信息(n-1个格子)。初始化所有结点的parent,lchild,rchild= -1,表示为无。有权值的赋予权值,否则赋为-1。
  3. 不断在数组中寻找权值最小的两个结点, 将这两个结点生成的二叉树的根结点顺序加入到数组[n,N-1],并更新它们的parent,lchild,rchild,weight。直到数组满,哈夫曼树形成。
  4. ps:值得注意的是select函数的实现思想,借鉴的网友的代码,思想很简单,s1和s2先存数组的前两个数,若下一个数小于其中的任意一个,则留下两个数中较小的一个,再留下该数,直到数组走完,留下了最小和次小的数。(也可对权值冒泡排序选择最小和次最小)
#include <iostream>
#include <cstdio>
#include <cstdlib>

using namespace std;

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

/*
根据哈夫曼算法:
1.若给定n个权值的结点构造n棵二叉树, 其中n棵二叉树的根结点分别为这n个结点,
且其没有左右子树,则这n棵二叉树构成的集合记为为集合F ={T1,T2,T3...Tn} 
2.将集合F中根结点权值之和最小的两棵二叉树作为一个新增结点的左右子树,新增结点的权
值为这两棵二叉树的权值和,将该新增结点构造的二叉树加入集合F中,并从F中删除这两棵树。
3.重复步骤2直到集合F中只含有一棵树为止。(此时该树即为所求哈夫曼树)
*/


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

typedef char** HuffmanCode;

void HuffmanCoding(HTree& HT,HuffmanCode& HC,int *w,int n);
void select(HTree HT,int t,int&s1,int&s2);

void HuffmanCoding(HTree& HT,HuffmanCode& HC,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)
	{
		//-1表示不存在
		*(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<7;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[0..n]中选择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;
	}
}

void select(HTree HT,int t,int&s1,int&s2)
{
	//在HT[0..n]中选择parent为0且weight最小的两个结点,其序号分别为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[4]={7,5,2,4};
	HTree HT;
	HuffmanCode HC;
	HuffmanCoding(HT,HC,w,4);
	cout<<'\n'<<"完成后:"<<endl;
	cout<<"双亲"<<'\t'<<"左孩子"<<'\t'<<"右孩子"<<'\t'<<"权值"<<endl;
	for(int i=0;i<7;i++)
	{
		cout<<HT[i].parent<<'\t'<<HT[i].lchild<<'\t'<<HT[i].rchild<<'\t'<<HT[i].weight<<endl;
	}
	return 0;
}

运行结果:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值