哈夫曼树与哈夫曼编码

一.最优树的定义:在含有n个叶子节点,并带相同权值的m叉树中,必存在一棵带权路径长度最短的树,称为“最优树”。


二.最优树的构造:(以二叉树为例)

(a).根据给定的n个权值为{w1,w2,...wn},构造n棵二叉树的集合F={T1,T2,...Tn},其中,每棵二叉树中均只含有一个带权值为wi的根结点,左右子树均为空;

(b).在F中选取其根结点的权值为最小的两棵二叉树,分别作为左右子树构造一棵新的二叉树,并置这棵二叉树根结点的权值为其左右子树根结点的权值之和;

(c).从F中删除这两棵子树,同时加入刚生成的新树;

(d).重复步骤(a),(b),直至F中只含有一棵树为止。

最优二叉树就是哈夫曼树。


三.前缀编码

任何一个字符的编码都不是同一字符集中其他字符编码的前缀,哈夫曼编码是一种最优前缀编码。

#include<iostream>
#include<string>
using namespace std;
#define MAXSIZE 50
typedef struct HTnode
{
	int weight;
	int parent;
	int lchild;
	int rchild;
}HTnode;         //结点类型由权值,双亲结点,左孩子结点和右孩子结点完成
typedef struct HuffmanTree
{
	HTnode HT[MAXSIZE+1];
}HuffmanTree;
typedef char* *HuffmanCode;   //动态分配数组存储哈夫曼编码
typedef char* pchar;
int SelectMin(HuffmanTree &T,int k)     //从前k棵二叉树中选取权值最小的二叉树
{
	int pos;
	int min=1000;
	for(int i=1;i<=k;i++)
	{
		if(T.HT[i].weight<min&&T.HT[i].parent==0)
		{
			min=T.HT[i].weight;
			pos=i;
		}
	}
	T.HT[pos].parent=k+1;
	return pos;
}
void Select2Min(HuffmanTree &T,int k,int &pos1,int &pos2)   //选取两颗权值最小的二叉树,返回它们在数组中的位置
{
	pos1=SelectMin(T,k);
	pos2=SelectMin(T,k);
}

void CreateHuffmanTree(HuffmanTree &T,int n,int w[])
{
	int i;
	int pos1,pos2;   //记录最小的两个元素的位置
	int m=2*n-1;
	int *p=w;
	for(i=1;i<=n;i++)
	{
		T.HT[i].weight=*p;
		T.HT[i].parent=0;
		T.HT[i].lchild=0;
		T.HT[i].rchild=0;
		p++;
	}
	for(i=n+1;i<=m;i++)
	{
		T.HT[i].weight=0;
		T.HT[i].parent=0;
		T.HT[i].lchild=0;
		T.HT[i].rchild=0;
	}     
	//以上完成对HuffmanTree的初始化
	for(i=n+1;i<=m;i++)
	{
		Select2Min(T,i-1,pos1,pos2);
		T.HT[i].lchild=pos1;
		T.HT[i].rchild=pos2;
		T.HT[i].weight=T.HT[pos1].weight+T.HT[pos2].weight;
	}
	T.HT[m].parent=-1;
	//实现HuffmanTree的构造
}

void Reverse(char* str)
{
	int i,j,l;
	char c;
	l=strlen(str);
	for(i=0,j=l-1;j>=i;i++,j--)
	{
		c=str[i];
		str[i]=str[j];
		str[j]=c;
	}
}

void GetHuffmanCode(HuffmanTree T,HuffmanCode &HC,int n)
{
	int i,j;
	int p;
	char buffer[10];
	for(i=1;i<=n;i++)
	{
		j=0;
		p=T.HT[i].parent;
		int k=i;               //k记录父结点p的孩子结点
		while(p!=-1)
		{
			if(T.HT[p].lchild==k)   //如果是左孩子,编码为‘0’
			{
				buffer[j++]='0';
			}
			else
			{
				buffer[j++]='1';
			}
			k=p;
			p=T.HT[p].parent;		
		}
		buffer[j]='\0'; 
		Reverse(buffer);
		HC[i]=new char[10];
		strcpy(HC[i],buffer);
	}
}

void main()
{
	HuffmanTree T;
	char HuffmanString[]="ABCD";
	int n=strlen(HuffmanString);
	int w[]={1,3,6,9};
	CreateHuffmanTree(T,n,w);
	cout<<"创建的HuffmanTree为:"<<endl;
	cout<<'	'<<"weight"<<'	'<<"parent"<<'	'<<"lchild"<<'	'<<"rchild"<<endl;
	for(int i=1;i<=2*n-1;i++)
	{
		cout<<i<<'	'<<T.HT[i].weight<<'	'<<T.HT[i].parent<<'	'<<T.HT[i].lchild<<'	'<<T.HT[i].rchild<<endl;
	}
	HuffmanCode HC=new pchar[n+1];
	GetHuffmanCode(T,HC,n);
	for(i=1;i<=n;i++)
	{
		cout<<"第"<<i<<"个字符的哈夫曼编码为:"<<HC[i]<<endl;
	}
}
-------------------------------------------------------------------------------------------------------------

运行结果:

创建的HuffmanTree为:
        weight  parent  lchild  rchild
1       1       5       0       0
2       3       5       0       0
3       6       6       0       0
4       9       7       0       0
5       4       6       1       2
6       10      7       5       3
7       19      -1      4       6
第1个字符的哈夫曼编码为:100
第2个字符的哈夫曼编码为:101
第3个字符的哈夫曼编码为:11
第4个字符的哈夫曼编码为:0
Press any key to continue

-------------------------------------------------------------------------------------------------------------

-------------------------------------------------

To_make_progress,everyday!

-------------------------------------------------


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值