数据结构之哈夫曼树
數據結構之哈夫曼樹
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?<stdio.h>
#include?<stdlib.h>
#include?<string.h>
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;
}
總結
- 上一篇: C++二叉树的建立与遍历
- 下一篇: 数据结构之查找二叉树