# 哈夫曼樹
哈夫曼樹是在 n 個帶權葉子節點構成的二叉樹中,帶權路徑長度最小的二叉樹。一棵哈夫曼樹是一棵二叉樹,其中沒有度為1的節點,因此具有 n 個葉子節點的哈弗曼樹,共有 2n-1 個節點。
## 哈夫曼樹的構造算法
1. 根據給定的n個權值(w1,w2, …,wn) 對應節點構成n棵二叉樹的森林T=(T1,T2,… ,Tn) ,其中每棵二叉樹Ti (1≤i≤no) 中都只有一個帶權值為wi的根節點,其左、右子樹均為空。
2. 在森林T中選取兩棵節點的權值最小的子樹分別作為左、右子樹構造一棵新的二叉樹,且置新的二叉樹的根節點的權值為其左、右子樹上根的權值之和。
3. 在森林 T 中用新得到的二叉樹代替這兩棵樹。
4. 重復2和3,直到T只含一棵樹為止,這棵樹便是哈夫曼樹。
### 節點類型
```C
typedef struct{
ElemType data;
float weight;
int parent;
int lchild;
int rchild;
}HTNode;
```
### 構造算法
```C
#define Max 32767
void CreateHT(HTNode ht[], int n)
{
int i, j, k, lnode, rnode;
float min1, min2;
// 所有節點的相關域置 -1
for(i=0;i<2*n-1;i++)
ht[i].parent=ht[i].lchild=ht[i].rchild=-1;
// 構造哈夫曼樹
for(i=n;i<2*n-1;i++){
min1=min2=Max;
lnode=rnode=-1;
for(k=0;k<=i-1;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[lnode].parent=i;ht[rnode].parent=i;
ht[i].weight=ht[lnode].weight+ht[rnode].weight;
ht[i].lchild=lnode;ht[i].rchild=rnode;
}
}
```
## 哈夫曼編碼
頻率越高的采用越短的編碼。
### 哈夫曼編碼的節點類型
```C
typedef struct{
char cd[N];
int start;
}HCode;
```
### 求哈夫曼樹對應的哈夫曼編碼
```C
void CreateHCode(HTNode ht[], HCode hcd[], int n)
{
int i, f, c;//father、child
HCode hc;
// 根據哈夫曼樹求哈夫曼編碼
for(i=0;i<n;i++){
hc.start=n;c=i;
f=ht[i].parent;
// 循環直至根節點
while(f!=-1){
// 當前節點是雙親節點的左孩子
if(ht[f].lchild==c)
hc.cd[hc.start--]='0';
// 當前節點是雙親節點的右孩子
else
hc.cd[hc.start--]='1';
c=f;f=ht[f].parent;
}
hc.start++;
hcd[i]=hc;
}
}
```