數據結構(十)哈夫曼樹

哈夫曼樹

1. 定義

帶權路徑長度(WPL):設二叉樹有 nn 個葉子結點,每個葉子結點帶有權值 wkw_k,從根結點到每個葉子結點的長度爲 lkl_k,則每個葉子結點的帶權路徑長度之和就是:WPL = k=1nwklk\sum_{k=1}^{n}w_kl_k

最優二叉樹或哈夫曼樹: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;
} 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章