哈夫曼樹
1. 定義
帶權路徑長度(WPL):設二叉樹有 個葉子結點,每個葉子結點帶有權值 ,從根結點到每個葉子結點的長度爲 ,則每個葉子結點的帶權路徑長度之和就是:WPL =
最優二叉樹或哈夫曼樹:WPL 最小的二叉樹
2. 哈夫曼樹的構造
- 每次把權值最小的兩顆二叉樹合併
3. 哈夫曼樹的特點
- 沒有度爲 1 的結點
- n 個葉結點的哈夫曼樹共有 2n-1 個結點
- 哈夫曼樹的任意非葉結點的左右子樹交換後仍是漢夫曼樹
- 對同一組權值,可能存在不同構的多棵哈夫曼樹
4. 最小堆實現哈夫曼樹
剛開始挺懵逼,堆裏面怎麼還出哈夫曼樹了呢…看姥姥留言堆裏本來就是放東西的,既然可以放數…那爲什麼不能放樹,醍醐灌頂
#include<iostream>
#include<malloc.h>
#define MaxSize 1000
#define MinData -1000
int A[] = {1,3,5,8}; // 預先定義好一組權值
int A_length = 4; // 定義其長度
typedef struct HeapStruct *MinHeap;
typedef struct TreeNode *HuffmanTree;
struct HeapStruct{ // 存放哈夫曼樹的堆
HuffmanTree *data; // 存值的數組
int size; // 堆的當前大小
int capacity; // 最大容量
};
struct TreeNode{ // 哈夫曼樹
int weight; //權值
HuffmanTree Left; // 左子樹
HuffmanTree right; // 右子樹
};
using namespace std;
MinHeap create(); // 初始化堆
HuffmanTree Create(); // 初始化哈夫曼樹
void sort(MinHeap H,int i); // 調整子最小堆
void adjust(MinHeap H); // 調整最小堆
void BuildMinHeap(MinHeap H); // 建堆
HuffmanTree Delete(MinHeap H); // 刪除最小堆元素
void Insert(MinHeap H,HuffmanTree Huff); // 插入最小堆元素
void PreOrderTraversal(HuffmanTree Huff); // 先序遍歷
HuffmanTree Huffman(MinHeap H); // 哈夫曼樹的構建
// 初始化堆
MinHeap create(){
MinHeap H;
HuffmanTree Huff;
H = (MinHeap)malloc(sizeof(struct HeapStruct));
H->data = (HuffmanTree *)malloc(sizeof(struct TreeNode) * (MaxSize+1));
H->capacity = MaxSize;
H->size = 0;
// 給堆置哨兵
Huff = Create();
Huff->weight = MinData;
H->data[0] = Huff;
return H;
}
// 初始化哈夫曼樹
HuffmanTree Create(){
HuffmanTree Huff;
Huff = (HuffmanTree)malloc(sizeof(struct TreeNode));
Huff->weight = 0;
Huff->Left = NULL;
Huff->right = NULL;
return Huff;
}
// 調整子最小堆
void sort(MinHeap H,int i){
int parent,child;
int tmp = H->data[i]->weight; // 取出當前"根結點"值
for(parent=i;parent*2<=H->size;parent = child){
child = 2 * parent;
if((child!=H->size) && (H->data[child+1]->weight < H->data[child]->weight))
child++;
if(H->data[child]->weight >= tmp)
break;
else
H->data[parent]->weight = H->data[child]->weight;
}
H->data[parent]->weight = tmp;
}
// 調整最小堆
void adjust(MinHeap H){
for(int i =H->size/2;i>0;i--)
sort(H,i);// 每個"子最小堆"調整
}
// 建堆
void BuildMinHeap(MinHeap H){
// 將權值讀入堆中
HuffmanTree Huff;
for(int i=0;i<A_length;i++){
Huff = Create();
Huff->weight = A[i];
H->data[++H->size] = Huff;
}
// 調整堆
adjust(H);
}
// 刪除最小堆元素
HuffmanTree Delete(MinHeap H){
int parent,child;
HuffmanTree T = H->data[1]; // 取出根結點的哈夫曼樹
HuffmanTree tmp = H->data[H->size--]; // 取出最後一個結點哈夫曼樹的權值
for(parent=1;parent*2<=H->size;parent = child){
child = 2 * parent;
if((child!=H->size) && (H->data[child+1]->weight < H->data[child]->weight))
child++;
if(H->data[child]->weight >= tmp->weight)
break;
else
H->data[parent] = H->data[child];
}
H->data[parent] = tmp;
// 構造一個 HuffmanTree 結點,附上剛纔取出來的權值,返回該結點
return T;
}
// 插入一個哈夫曼樹
void Insert(MinHeap H,HuffmanTree Huff){
int weight = Huff->weight; // 取出權值
int i = ++H->size;
for(;H->data[i/2]->weight > weight;i/=2)
H->data[i] = H->data[i/2];
H->data[i] = Huff;
}
//遍歷
void PreOrderTraversal(HuffmanTree Huff){
if(Huff){
cout<<Huff->weight<<" ";
PreOrderTraversal(Huff->Left);
PreOrderTraversal(Huff->right);
}
}
// 哈夫曼樹的構造
HuffmanTree Huffman(MinHeap H){
HuffmanTree T;
BuildMinHeap(H); // 建堆
int times = H->size;
// 做 times-1 次合併
for(int i=1;i<times;i++){
T = (HuffmanTree)malloc(sizeof(struct TreeNode));
T->Left = Delete(H); // 從堆中刪除一個結點,作爲新 T 的左子結點
T->right = Delete(H); // 從堆中刪除一個結點,作爲新 T 的右子結點
T->weight = T->Left->weight + T->right->weight; // 重新計算權值
Insert(H,T); // 再加進堆中
}
T = Delete(H);
return T;
}
int main(){
MinHeap H;
HuffmanTree Huff;
H = create();
Huff = Huffman(H);
PreOrderTraversal(Huff);
return 0;
}