定義:
它是由n個帶權葉子結點構成的所有二叉樹中帶權路徑長度最短的二叉樹。因爲這種樹最早由哈夫曼(Huffman)研究,所以稱爲哈夫曼樹,又叫最優二叉樹。
1.初始化:
根據給定的n個權值{w1,w2,…wn}構成n棵二叉樹的集合F={T1,T2,..,Tn},其中每棵二叉樹Ti中只有一個帶權wi的根結點,左右子樹均空。
2. 找最小樹:
在F中選擇兩棵根結點權值最小的樹作爲左右子樹構造一棵新的二叉樹,且至新的二叉樹的根結點的權值爲其左右子樹上根結點的權值之和。
3. 刪除與加入:
在F中刪除這兩棵樹,並將新的二叉樹加入F中。
4. 判斷:
重複前兩步(2和3),直到F中只含有一棵樹爲止。該樹即爲哈夫曼樹
代碼實現:
由於本身節點的特殊性(同時要記錄雙親節點和孩子節點)所以這裏採用靜態鏈表來實現構造
typedef struct
{
char data;//存放節點元素
int weight;//權值
int parent;//雙親節點下標
int lch;//左孩子下標
int rch;//右孩子
}HTNode;
構造哈弗曼樹:
void CreateHT(HTNode ht[], int n)
{
int i, k, lnode, rnode;
int min1, min2;
for (i = 0;i < 2 * n - 1;i++) //初始化
ht[i].parent = ht[i].lch = ht[i].rch = -1;
for (i = n;i < 2 * n - 1;i++)//建樹
{
min1 = min2 = 32767;
lnode = rnode = -1;
for (k = 0;k < i;k++)//每次尋找一個最小和一個次小權值的節點並將合併後的節點加入森林
if (ht[k].parent == -1)
{
if (ht[k].weight < min1)
{
min2 = min1;
rnode = lnode;
min1 = ht[k].weight;
lnode = k;
}
else if (ht[k].weight < min2)
{
min2 = ht[k].weight;
rnode = k;
}
}
ht[i].weight = ht[rnode].weight + ht[lnode].weight;//將合併後的雙親節點依次放在數組末端並記錄孩子節點
ht[i].lch = lnode;
ht[i].rch = rnode;
ht[lnode].parent = i;//標記雙親節點下標
ht[rnode].parent = i;
}
}
構造哈弗曼編碼節點:
typedef struct
{
int cd[100];//存放節點的編碼
int start;//標記編碼的開始下標
}HCode;
哈弗曼編碼:
void CreateHCode(HTNode ht[], HCode hcd[], int n)
{
int i, parents, present;
HCode hc;
for (i = 0;i < n;i++)
{
hc.start = n;//hcd[start]~hcd[n]用於存放編碼
present = i;//從第i個元素依次編碼
parents = ht[i].parent;//記錄當前節點的雙親節點下標
while (parents != -1)//循環直到樹根節點
{
if (ht[f].lch == present)//當前節點是左孩子記爲0
hc.cd[hc.start--] = 0;
else
hc.cd[hc.start--] = 1;//當前節點是右孩子記爲1
present = parents;// 向上循環
parents = ht[parents].parent;
}
hc.start++;//start指向編碼開始下標
hcd[i] = hc;//存放編碼
}
}