分类: C/C++
1.哈夫曼树简介
(1) WPL = 7*2+5*2+2*2+4*2 = 36;
(1) WPL = 7*1+5*2+2*3+4*3 = 35;经过证明此为最小的WPL即为哈夫曼树
在解决某些问题时,利用哈夫曼树可以找到最佳判定算法,因为某些条件出现的频率不一样,这样导致了同一段代码在不同的环境下取得的效果不是最优的。
2. 哈夫曼树的构造算法
假设有n个权值,则构造出的哈夫曼树有n个叶子结点。 n个权值分别设为 w1、w2、…、wn,则哈夫曼树的构造规则为:
(1) 将w1、w2、…,wn看成是有n 棵树的森林(每棵树仅有一个结点);
(2) 在森林中选出两个根结点的权值最小的树合并,作为一棵新树的左、右子树,且新树的根结点权值为其左、右子树根结点权值之和;
(3)从森林中删除选取的两棵树,并将新树加入森林;
(4)重复(2)、(3)步,直到森林中只剩一棵树为止,该树即为所求得的哈夫曼树。
构造过程如下:
(a) 有权值为1,2,3,4四棵树;
(b) 由于树1,2的权值处于最小和次最小,所以选中,并合成为一棵树,小的权值位于左边;
(c) 从3,4,(1,2 = 3)三棵树里面选择权值最小的和次小的,我们选中3和(1,2)
合成新树(3,(1,2)= 6);
(d) 最后选出新树(4,(3,(1, 2)))
(来自:http://baike.baidu.com/view/127820.htm)
3. 哈夫曼树具体实现
需要考虑的问题:
(1) 用什么样的存储结构;
(2) 怎么选择选择最小和次小权值的树;
(3) 怎么存放合成的新树
如果我们采用
Struct node
{
Int key;
Struct node *l;
Struct node *r;
}
的存储结构的话,可以采用数组的链式结构,并设计标记数组如下:
(我们以4个初始树为例子)
标记数组:(有则标记为1,否则为0)
Struct node n1 | Struct node n1 | Struct node n1 | Struct node n1 |
存储数组
Struct node n1 | Struct node n1 | Struct node n1 | Struct node n1 |
第一次选择为1,2树,合成新树,我们可以统一放在最小树的位置上(也可以放在大树位置上),所以新树放于树1 的位置并更新其权值为两者之和,其状态为:
标记数组:(有则标记为1,否则为0)
1 | 0 | 1 | 1 |
存储数组
Struct node n1 | Free() | Struct node n1 | Struct node n1 |
这样存储结构的问题解决了,其实做到这里我们应该比较清楚后面怎么做了,当然选择出最小值和次小值为比较简单的算法了。
例:设有8个字符{A,B,C,D,E,F,G,H},其概率为{0.05,0.29,0.07,0.08,0.14,0.23,0.03,0.11},设其权值用整数表示为 {5,29,7,8,14,23,3,11},其哈夫曼树如图1所示。
实现代码如下:
#include
#include
#include
struct node
{
int key;
struct node *l;
struct node *r;
};
typedef struct node *pnode;
int mark[100];
struct node huffman[100];
void PrintNode(const pnode node)
{
printf("key = %d \n", node->key);
}
void PreOrder(pnode T)
{
if(T)
{
PrintNode(T);
PreOrder(T->l);
PreOrder(T->r);
}
}
void Select(int *mark, struct node *huffman, int size, int *choose)
{
int i;
for(i = 0; i< size; i++)
{
if(mark[i])
{
choose[0] = i;
i++;
break;
}
}
choose[1] = choose[0];
for(;i < size;i++)
{
if(mark[i])
{
if(huffman[choose[0]].key >= huffman[i].key)
{
choose[1] = choose[0];
choose[0] = i;
}
else if(huffman[choose[1]].key > huffman[i].key) choose[1] = i;
}
}
}
void Choose(int *mark, struct node *huffman, int size, int *choose)
{
int i;
int minkey = 0;
int tkey = 0;
int temp = 0;
for(i = 0; i< size; i++)
{
if(mark[i])
{
minkey = i;
i++;
break;
}
}
tkey = minkey;
for(; i< size; i++)
{
if(mark[i])
{
if(huffman[i].key < huffman[minkey].key)
{
tkey = minkey;
minkey = i;
}
if(tkey == minkey)
tkey = i;
if(huffman[tkey].key > huffman[i].key && i != minkey)
{
tkey = i;
}
}
}
choose[0] = minkey;
choose[1] = tkey;
}
pnode HuffmanTree(int *mark, struct node *huffman, int size)
{
int choose[2];
int i;
pnode mynode;
for(i = 0; i < size-1; i++)
{
Select(mark, huffman, size, choose);
mynode = (pnode)malloc(sizeof(struct node));
mynode->key = huffman[choose[0]].key+huffman[choose[1]].key;//更新key值
mynode->l = (pnode)malloc(sizeof(struct node));
mynode->l->key = huffman[choose[0]].key;
mynode->l->l = huffman[choose[0]].l;
mynode->l->r = huffman[choose[0]].r;
mynode->r = &huffman[choose[1]];
huffman[choose[0]] = *mynode;
mark[choose[1]] = 0;
free(mynode);
}
return &huffman[choose[0]];
}
int main(void)
{
int key[8] = {5,29,7,8,14,23,3,11};
int i;
pnode huffmantree;
memset(mark, -1, sizeof(mark));
memset(huffman, 0, sizeof(huffman));
for(i = 0; i < 8; i++)
{
huffman[i].key = key[i];
}
huffmantree = HuffmanTree(mark, huffman, 8);
PreOrder(huffmantree);
return 0;
}