哈夫曼树(最优二叉树)

最优二叉树,也称哈夫曼(Haffman)树,是指对于一组带有确定权值的叶结点,构造的具有最小带权路径长度的二叉树。
二叉树的路径长度则是指由根结点到所有叶结点的路径长度之和。如果二叉树中的叶结点都具有一定的权值,则可将这一概念加以推广。设二叉树具有n个带权值的叶结点,那么从根结点到各个叶结点的路径长度与相应结点权值的乘积之和叫做二叉树的带权路径长度,记为:


根据哈夫曼树的定义,一棵二叉树要使其WPL值最小,必须使权值越大的叶结点越靠近根结点,而权值越小的叶结点越远离根结点。哈夫曼(Haffman)依据这一特点提出了一种方法,这种方法的基本思想是:
(1)由给定的n个权值{W1,W2,…,Wn}构造n棵只有一个结点的二叉树,从而得到一个二叉树的集合F={T1,T2,…,Tn};
(2)在F中选取根结点的权值最小和次小的两棵二叉树,作为左、右子树构造一棵新的二叉树,这棵新的二叉树根结点的权值为其左、右子树根结点权值之和;
(3)在集合F中删除作为左、右子树的两棵二叉树,并将新建立的二叉树加入到集合F中;
(4)重复(2)(3)两步,当F中只剩下一棵二叉树时,这棵二叉树便是所要建立的哈夫曼树。

实现:

http://baike.baidu.com/link?url=NqG5sKag29DdmFEMrh7iZLscBgYHQz2pyZpNYeFTkmPfVYmcgEyu87JLinBANpD5#5_3

#include<iostream>
#include<stdlib.h>
usingnamespacestd;
constintMaxValue=10000;//初始设定的权值最大值
constintMaxBit=4;//初始设定的最大编码位数
constintMaxN=10;//初始设定的最大结点个数
structHaffNode//哈夫曼树的结点结构
{
intweight;//权值
intflag;//标记
intparent;//双亲结点下标
intleftChild;//左孩子下标
intrightChild;//右孩子下标
};
structCode//存放哈夫曼编码的数据元素结构
{
intbit[MaxBit];//数组
intstart;//编码的起始下标
intweight;//字符的权值
};
voidHaffman(intweight[],intn,HaffNodehaffTree[])
//建立叶结点个数为n权值为weight的哈夫曼树haffTree
{
intj,m1,m2,x1,x2;
//哈夫曼树haffTree初始化。n个叶结点的哈夫曼树共有2n-1个结点
for(inti=0;i<2*n-1;i++)
{
if(i<n)
haffTree[i].weight=weight[i];
else
haffTree[i].weight=0;
haffTree[i].parent=0;
haffTree[i].flag=0;
haffTree[i].leftChild=-1;
haffTree[i].rightChild=-1;
}
//构造哈夫曼树haffTree的n-1个非叶结点
//for(inti=0;i<n-1;i++)
for(inti=0;i<n-1;i++)
{
m1=m2=MaxValue;
x1=x2=0;
//for(j=0;j<n+i;j++)
for(j=i;j<n+i;j++)//循环找出所有权重中,最小的二个值--morgan
{
if(haffTree[j].weight<m1&&haffTree[j].flag==0)
{
m2=m1;
x2=x1;
m1=haffTree[j].weight;
x1=j;
}
else
if(haffTree[j].weight<m2&&haffTree[j].flag==0)
{
m2=haffTree[j].weight;
x2=j;
}
}//endfor
//将找出的两棵权值最小的子树合并为一棵子树
haffTree[x1].parent=n+i;
haffTree[x2].parent=n+i;
haffTree[x1].flag=1;
haffTree[x2].flag=1;
haffTree[n+i].weight=haffTree[x1].weight+haffTree[x2].weight;
haffTree[n+i].leftChild=x1;
haffTree[n+i].rightChild=x2;
}
}
voidHaffmanCode(HaffNodehaffTree[],intn,CodehaffCode[])
//由n个结点的哈夫曼树haffTree构造哈夫曼编码haffCode
{
Code*cd=newCode;
intchild,parent;
//求n个叶结点的哈夫曼编码
for(inti=0;i<n;i++)
{
//cd->start=n-1;//不等长编码的最后一位为n-1,
cd->start=0;//,----修改从0开始计数--morgan
cd->weight=haffTree[i].weight;//取得编码对应权值的字符
child=i;
parent=haffTree[child].parent;
//由叶结点向上直到根结点
while(parent!=0)
{
if(haffTree[parent].leftChild==child)
cd->bit[cd->start]=0;//左孩子结点编码0
else
cd->bit[cd->start]=1;//右孩子结点编码1
//cd->start--;
cd->start++;//改成编码自增--morgan
child=parent;
parent=haffTree[child].parent;
}
//保存叶结点的编码和不等长编码的起始位
//for(intj=cd->start+1;j<n;j++)
for(intj=cd->start-1;j>=0;j--)//重新修改编码,从根节点开始计数--morgan
haffCode[i].bit[cd->start-j-1]=cd->bit[j];
 
haffCode[i].start=cd->start;
haffCode[i].weight=cd->weight;//保存编码对应的权值
}
}
intmain()
{
inti,j,n=4,m=0;
intweight[]={2,4,5,7};
HaffNode*myHaffTree=newHaffNode[2*n-1];
Code*myHaffCode=newCode[n];
if(n>MaxN)
{
cout<<"定义的n越界,修改MaxN!"<<endl;
exit(0);
}
Haffman(weight,n,myHaffTree);
HaffmanCode(myHaffTree,n,myHaffCode);
//输出每个叶结点的哈夫曼编码
for(i=0;i<n;i++)
{
cout<<"Weight="<<myHaffCode[i].weight<<"Code=";
//for(j=myHaffCode[i].start+1;j<n;j++)
for(j=0;j<myHaffCode[i].start;j++)
cout<<myHaffCode[i].bit[j];
m=m+myHaffCode[i].weight*myHaffCode[i].start;
cout<<endl;
}
cout<<"huffman'sWPLis:";
cout<<m;
cout<<endl;
return0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值