Huffman树又叫做最优二叉树,常常会涉及到树的带权路径长度的概念,即WPL的概念,同时又经常会考到haffman编码及其代码实现方式
下面描述下haffman算法的基本思想:
1、把w1、w2......wn构建成n个只有根节点的二叉树
2、选出n个子树中节点值最小的两个子树,合并成一个子树,节点的权值为两个子树的节点和
3、把新的节点加入到原先的子树中,重复1,2的操作直到只剩下一棵树,这个就是haffman树
haffman编码简单介绍:
哈夫曼编码(Huffman Coding)是一种编码方式,哈夫曼编码是可变字长编码(VLC)的一种。Huffman于1952年提出一种编码方法,该方法完全依据字符出现概率来构造异字头的平均长度最短的码字,有时称之为最佳编码,一般就叫作Huffman编码(有时也称为霍夫曼编码)。
haffman编码的获取的方式:
因为开始的时候是从所有的节点中选取权值最小的节点开始的,而且有权值的节点都是叶子节点,所以必须从叶子节点开始遍历,从而需要知道各个节点的父亲节点的原因,而且获取的编码是逆序的,最后还需要通过逆序操作实现正确的haffman编码的获取
结合严蔚敏数据结构和算法的haffman那章的图6.22的那个例子实现haffman树的构建和haffman编码的获取的C++代码如下:
#include <iostream>
using namespace std;
const int MaxValue = 10000;
const int MaxBit = 10; //最大的编码位数
const int NodeNum = 10; //测试节点数
struct HaffNode{
int weight;
int visited;
int parent;
int leftchild;
int rightchild;
};
struct CodeNode{
int codeBit[MaxBit];
int start; //标记haffman编码的位数
int weight;
};
void Haffman(int weight[],int n,HaffNode haffTree[]){
//建立haffman树
int j,min1,min2,index1,index2;
//haffman树初始化
for(int i=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].visited = 0;
haffTree[i].leftchild = -1;
haffTree[i].rightchild = -1;
}
//haffman树构造
for(int i=0;i<n-1;i++){
min1 = min2 = MaxValue;
index1 = index2 = 0;
for(j=0;j<n+i;j++){ //找到最小的两个节点,注意因为合并后新的节点加入所以为j<n+i
int door = min1>=min2?min1:min2; //阙值
if(haffTree[j].weight<tempMin && haffTree[j].visited==0){
if(min1>=min2){
min1 = haffTree[j].weight;
index1 = j;
}else{
min2 = haffTree[j].weight;
index2 = j;
}
}
}//end for 并且合并两个最小的节点为一个新的节点
haffTree[index1].parent = n+i;
haffTree[index2].parent = n+i;
haffTree[index1].visited = 1;
haffTree[index2].visited = 1;
haffTree[n+i].weight = haffTree[index1].weight+haffTree[index2].weight;
haffTree[n+i].leftchild = index1;
haffTree[n+i].rightchild = index2;
}
}
void haffmanCode(HaffNode haffTree[],int n,CodeNode haffCode[]){
//由n个节点的haffman树构造haffman编码
CodeNode *node = new CodeNode();
int child,parent;
for(int i=0;i<n;i++){
node->start = 0;
node->weight = haffTree[i].weight;
child = i;
parent = haffTree[child].parent;
//由叶节点逆向到根节点
while(parent!=0){
if(haffTree[parent].leftchild==child){
node->codeBit[node->start++] = 0;
}else{
node->codeBit[node->start++] = 1;
}
child = parent;
parent = haffTree[child].parent;
}
for(int j=node->start-1;j>=0;j--){ //获取从根节点到叶子的haffman序列
haffCode[i].codeBit[node->start-j-1] = node->codeBit[j];
}
haffCode[i].start = node->start;
haffCode[i].weight = node->weight;
}
}
int main(){
int n = 4,total = 0;//测试数据,用的是严蔚敏书的图6.22那个数据
int weight[] = {5,7,4,2};
HaffNode *haffTree = new HaffNode[2*n-1];
CodeNode *haffCode = new CodeNode[n];
Haffman(weight,n,haffTree);
haffmanCode(haffTree,n,haffCode);
//输出节点的haffMan编码
for(int i=0;i<n;i++){
cout<<"weight = "<<haffCode[i].weight<<" Code = ";
for(int j=0;j<haffCode[i].start;j++){
cout<<haffCode[i].codeBit[j];
}
total += haffCode[i].weight*haffCode[i].start;
cout<<endl;
}
cout<<"The WPL is: ";
cout<<total<<endl;
return 0;
}