哈夫曼树
给定n个权值作为n个叶子结点,构造一棵二叉树,若带权路径长度达到最小,称这样的二叉树为最优二叉树,也称为哈夫曼树(Huffman Tree)。哈夫曼树是带权路径长度最短的树,权值较大的结点离根较近。
给定如下数据:
要求构造哈夫曼树、输出哈夫曼编码以及计算平均查找长度。
根据哈夫曼树的定义,我们可以如下进行构造:
定义一个map 将单词与频度对应起来,再根据频度进行构造树。
构造步骤如下:
先从上面选出两个最小的(上面的频度恰好是按降序排列的):
此时123和124合成了一个新的节点245,
用形成的节点和剩下没被选中的节点重复上面步骤,具体如下:
继续选最小两个····
继续选最小两个····
····
以此类推…
最后成树如下:
具体过程如上。权值是口算的,如果权值算错请多谅解,看懂步骤就好。
哈夫曼树可以不唯一,因为左右子树可以互换。
以下为代码部分,在这里我是用数组来存贮树节点的,数组大小为2n。
假设刚开始有n个节点,则最终形成的哈夫曼树有2n-1个节点。
因为此时的n个初始节点可全部看成树的n个叶子节点(实际也是如此),树的非叶子节点为n-1个,则总结点数m=2n-1,所以声明2n个节点空间刚好够用。坐标为0的空间不做处理(坐标1~n存贮n个初始节点),从坐标n+1开始形成哈夫曼树,最终坐标为2n-1时为树的根节点。
具体的请看里面的注释,因为和代码一起看才更容易懂。
以下为代码部分:
代码
#include<string>
#include<stdio.h>
#include<stdlib.h>
#include<iostream>
#include<queue>
#include<algorithm>
#include<map>
using namespace std;
const int nums= 15;
typedef struct{
int weight;
int parent,lchild,rchild;
}HTNode,*HuffmanTree;
void Select(HuffmanTree HT,int n,int &s1,int &s2){
//s1,s2分别是权值最小和次小的。
int minum;
for(int i=1;i<=n;i++){//初始化minum。parent为0(即表示 还没有被选择的节点)
if(HT[i].parent==0){
minum=i; break;
}
}
for(int i=1;i<=n;i++){
if(HT[i].parent==0){
if(HT[i].weight<HT[minum].weight)
minum=i;
}
}
s1=minum;//最小值
for(int i=1;i<=n;i++){
if(HT[i].parent==0 && i!=s1){
minum=i; break;
}
}
for(int i=1;i<=n;i++){
if(HT[i].parent == 0 && i != s1)
if(HT[i].weight < HT[minum].weight)
minum = i;
}
s2=minum;//次小值
return ;
}
void CreateHuffmanTree(HuffmanTree &HT,int n,int ar[]){
if(n<=1) return ;
int m=2*n-1;
int s1,s2,i;
//初始化
for(i=1;i<=m;i++){
HT[i].parent=0;
HT[i].lchild=0;
HT[i].rchild=0;
}
for(i=1;i<=n;i++){
HT[i].weight=ar[i-1];
}
//构造哈夫曼树
for(int i=n+1;i<=m;i++){
//从第n+1个位置开始,,在前n个节点中选择最小的两个节点 在n+1的位置形成新节点。
//进入下一个循环(即i++),则把新形成的节点包括进去比较选择最小两个。
Select(HT,i-1,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 SetHuffCode(HuffmanTree HT,int n,string code,map<int,string>&p){
for(int i=1;i<=n;i++){
int current=i;
int father=HT[i].parent;
int rem;
while(father){
if(HT[father].lchild==current)
code='0'+code;
else code='1'+code;
current=father;
father=HT[father].parent;
}
p[HT[i].weight]=code;
code.clear();
}
}
int main()
{
int ar[nums]={1192,677,541,518,462,450,242,195,190,181,174,157,138,124,123};
string ar_S[nums]={"The","of","a","to","and","in","that","he","is","at","on","for","His","are","be"};
map<int,string>p_str;
map<int,string>p_code;
for(int i=0;i<nums;i++) p_str[ar[i]]=ar_S[i];
HuffmanTree HT=(HuffmanTree)malloc((2*nums)*sizeof(HTNode));
CreateHuffmanTree(HT,nums,ar);
SetHuffCode(HT,nums,"",p_code);
cout<<"The HuCode of strs:"<<endl;
int j=0,m=0;
double lenght=0;
for(int i=0;i<nums;i++){
cout<<p_str[ar[i]]<<'\t'<<ar[i]<<'\t'<<p_code[ar[i]]<<endl;
j=p_code[ar[i]].size();
m+=ar[i];
lenght+=ar[i]*j;
}
cout<<"Aver:"<<1.0*lenght/m<<endl;
system("pause");
return 0;
}
完结撒花。