一.最优树的定义:在含有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!
-------------------------------------------------