Huffman Tree
赫夫曼树(Huffman Tree),表示带权路径长度最短的树,简称为最优树。
首先来看一下相关的基本概念。
基本概念
1、路径长度
路径长度表示树中的两个结点之间的路径数。树的路径长度则表示从树根开始到每一个结点的路
2、径长度之和
如下图所示,结点a与根结点的路径长度为2,树的路径长度为2+2+1=5。
3、带权路径长度
当树的每个结点带有一定的权重时,结点的带权路径长度则表示从该结点到树根之间的路径长度与该结点的权重的乘积。而树的带权路径长度则表示树中所有叶子结点的带权路径长度的总和。
如上图所示,结点a的带权路径长度为:2*11=22,结点b的带权路径长度为2*5=10,结点c的带权路径长度为1*10=10。整个树的带权路径长度为2*11+2*5+1*10=42。
4、赫夫曼树
赫夫曼树则表示带权路径长度最短的树。上图的树当采用下图所示的形式时,其带权路径长度最短。
该树的带权路径长度为:5*2+2*10+1*11=41。
赫夫曼树构造方法
首先将n个结点的权值构成n颗二叉树的集合F={T1,T2,…,Tn},然后选择两个根结点权值最小的树做为左右子树构成一个新的二叉树,该二叉树的根结点的权值为左右子树上的根结点的权值的和。然后在F集合中删除该两个树,同时将新构成的树加入F集合。重复该过程,直到F只剩一棵树。
赫夫曼树编码
赫夫曼编码是一种二进制前缀编码规则。约定结点的左分支表示字符‘0’,右分支表示字符‘1’。如下图所示,结点c的赫夫曼编码为‘0’,结点b的赫夫曼编码为‘10’,结点c的赫夫曼编码为‘11’。
赫夫曼树和赫夫曼编码代码:
#include "stdafx.h" #include <iostream> using namespace std; typedef struct { int weight; int parent, lchild, rchild; }huffmanTreeNode, *huffmanTree; typedef char** huffmanCode; void select(huffmanTree &hT, int i, int &s1, int &s2){ int index = 1; int temp = hT[index].weight; while( index <=i){ if(hT[index].parent == 0) break; index++; } s1 = index; for(int j = 1;j<=i;j++){ if(hT[j].weight < hT[s1].weight && hT[j].parent == 0){ s1 = j; j++; } } index = 1; temp = hT[index].weight; while( index <=i){ if(hT[index].parent == 0 && index != s1) break; index++; } s2 = index; for(int j = 1;j<=i;j++){ if(hT[j].weight < hT[s2].weight && j != s1 && hT[j].parent == 0){ s2 = j; j++; } } int min, max; min = (s1 < s2)?s1:s2; max = (s1 > s2)?s1:s2; s1 = min; s2 = max; } void huffmancoding(huffmanTree &hT, huffmanCode &hC, int *w, int n){ if (n<1) return ; int m = 2*n - 1;//number of nodes hT = new huffmanTreeNode [m+1]; huffmanTree p; p = hT; p++; for(int i = 1; i<=n; ++i,++p,++w){ //*p = {*w, 0, 0, 0}; p->weight = *w; p->parent = 0; p->lchild = 0; p->rchild = 0; } for(int i = n+1;i<=m;++i,++p){ //*p = {0, 0, 0, 0}; p->weight = 0; p->parent = 0; p->lchild = 0; p->rchild = 0; } //打印初始的huffman HT cout<<"Try to print the initial huffman Tree table."<<endl; for(int i = 1;i<=m;++i){ cout<<hT[i].weight<<" "<<hT[i].parent<<" "<<hT[i].lchild<<" "<<hT[i].rchild<<endl; } int s1, s2; //构造huffman for(int i = n+1;i<=m;++i){ select(hT, i-1, s1, s2); if (s1<0 || s2<0) cout<<"ERROR"<<endl; 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; } //打印构造后的huffman cout<<"Try to print the created huffman Tree table."<<endl; for(int i = 1;i<=m;++i){ cout<<hT[i].weight<<" "<<hT[i].parent<<" "<<hT[i].lchild<<" "<<hT[i].rchild<<endl; } hC = new char* [(m + 1)*sizeof(char*)]; char *cd = new char [n*sizeof(char)]; cd[n-1] = '\0'; int start; int c , f; for(int i = 1; i<=n; i++){ start = n-1; for(c = i,f = hT[i].parent; f!=0; c = f, f = hT[f].parent){ if(hT[f].lchild == c) cd[--start] = '0'; else cd[--start] = '1'; } hC[i] = new char [(n-start)*sizeof(char)]; strcpy(hC[i], &cd[start]); } delete []cd; //打印赫夫曼编码 cout<<"Try to print huffman code"<<endl; for(int i = 1; i <= n; i++){ cout<<hC[i]<<endl; } } int _tmain(int argc, _TCHAR* argv[]) { int w[8] = {5,29,7,8,14,23,3,11}; int n = 8; huffmanTree hT; huffmanCode hC; huffmancoding(hT, hC, w, n); system("pause"); return 0; }