學弟講算法·哈夫曼樹與哈夫曼編碼

一、 實驗目的

通過C++實現對哈夫曼樹的建立與編碼

二、 實驗環境

Windows 10 1909

Devc++ 5.17

三、 實驗過程

3.1 建立哈夫曼樹

節點 權值
A 12
B 24
C 35
D 67
E 46
F 55

每次從所有節點中選出最小值節點與次小值節點,合併;重複操作至所有節點合併爲一棵樹

3.2 哈夫曼編碼

對建立好的哈夫曼樹,所有左兒子編爲0,右兒子編爲1,實現對各節點的編碼

四、 代碼實現

4.1 數據定義

//節點個數
#define LENGTH 6

// 用以進行哈夫曼編碼
int code[20];

// 用以保存每個節點的哈夫曼編碼
string huffman[LENGTH];

// 權值
int arr[LENGTH] = {12,24,35,67,46,55}; 

// 節點
char alph[LENGTH] = {'A','B','C','D','E','F'}; 

//節點
typedef struct Tree {
	//節點的權值 
	int data;
	Tree* leftChild;
	Tree* rightChild;
} Tree, *TreeList;

4.2 構建哈夫曼樹

//建哈夫曼樹函數,返回根節點
TreeList createTree(int arr[]) {
	//指針數組用來保存節點信息
	TreeList leaves[LENGTH];
	for (int i = 0; i < LENGTH; i++) {
		TreeList leaf = new Tree;
		leaf->data = arr[i];
		leaf->leftChild = leaf->rightChild = NULL;
		leaves[i] = leaf;
	}
	//哈夫曼樹的根節點
	TreeList root = NULL;
	//進行n-1次合併操作,建立哈夫曼樹 
	for (int i = 1; i < LENGTH; i++) {
		// min1表示最小權值的樹根結點的下標,min2爲次小權值節點的下標
		int min1 = -1, min2;
		//初始化min1與min2 
		for (int j = 0; j < LENGTH; j++) {
			if (leaves[j] != NULL && min1 == -1) {
				min1 = j;
				continue;
			}
			if (leaves[j] != NULL) {
				min2 = j;
				break;
			}
		}
		//找出最小值和次小值節點的下標
		for (int j = min2; j < LENGTH; j++) {
			if (leaves[j] != NULL) {
				if (leaves[j]->data < leaves[min1]->data) {
					min2 = min1;
					min1 = j;
				} else if (leaves[j]->data < leaves[min2]->data) {
					min2 = j;
				}
			}
		}
		//用最小權值樹和次小權值樹建立一棵新樹,root指向樹根結點
		root = new Tree;
		root->data = leaves[min1]->data + leaves[min2]->data;
		root->leftChild = leaves[min1];
		root->rightChild = leaves[min2];
		//將指向新樹的指針賦給leaves指針數組中min1位置
		leaves[min1] = root;
		// min2位置爲空
		leaves[min2] = NULL;
	}
	return root;
}

4.3 進行哈夫曼編碼

//根據權值獲取下標 
int getIndex(int weight){
	for(int i = 0 ;i<LENGTH;i++){
		if(weight == arr[i]){
			return i;
		}
	}
} 

//遞歸進行哈夫曼樹編碼,len是當前樹的層數
void huffmanCoding(TreeList& root, int len) {
	if (root == NULL) {
		return;
	}
	//若到葉子節點
	if (root->leftChild == NULL && root->rightChild == NULL) {
		//獲取該節點權值對應的字符下標 
		int index = getIndex(root->data);
		//保存該字符的哈夫曼編碼
		for (int i = 0; i < len; i++) {
			huffman[index].push_back(code[i] + '0');
		}
	}
	//否則繼續進行哈夫曼編碼的操作
	else {
		//左側分支都記爲零
		code[len] = 0;
		huffmanCoding(root->leftChild, len + 1);
		//右側分支都記爲一
		code[len] = 1;
		huffmanCoding(root->rightChild, len + 1);
	}
}

4.4 完整測試代碼

/*
        Name: Huffman tree coding
        Copyright:
        Author: YuanHao Li
        Date: 20/5/24 15:22
        Description:
*/

#include <stdio.h>
#include <string.h>
#include <iostream>
using namespace std;
#define LENGTH 6
//用以進行哈夫曼編碼
int code[20];
//用以保存哈夫曼編碼
string huffman[LENGTH];
int arr[LENGTH] = {12,24,35,67,46,55}; 
char alph[LENGTH] = {'A','B','C','D','E','F'}; 

typedef struct Tree {
	//節點的權值 
	int data;
	Tree* leftChild;
	Tree* rightChild;
} Tree, *TreeList;

//建哈夫曼樹,返回根節點
TreeList createTree(int arr[]) {
	//建立指針數組用來保存節點信息
	TreeList leaves[LENGTH];
	for (int i = 0; i < LENGTH; i++) {
		TreeList leaf = new Tree;
		leaf->data = arr[i];
		leaf->leftChild = leaf->rightChild = NULL;
		leaves[i] = leaf;
	}
	//建立一個節點作爲哈夫曼樹的根節點
	TreeList root = NULL;
	//建立哈夫曼樹 
	for (int i = 1; i < LENGTH; i++) {
		// min1表示最小權值的樹根結點的下標,min2爲次小權值節點的下標
		int min1 = -1, min2;
		//初始化min1與min2 
		for (int j = 0; j < LENGTH; j++) {
			if (leaves[j] != NULL && min1 == -1) {
				min1 = j;
				continue;
			}
			if (leaves[j] != NULL) {
				min2 = j;
				break;
			}
		}
		//找出最小值和次小值節點的下標
		for (int j = min2; j < LENGTH; j++) {
			if (leaves[j] != NULL) {
				if (leaves[j]->data < leaves[min1]->data) {
					min2 = min1;
					min1 = j;
				} else if (leaves[j]->data < leaves[min2]->data) {
					min2 = j;
				}
			}
		}
		//用最小權值樹和次小權值樹建立一棵新樹,root指向樹根結點
		root = new Tree;
		root->data = leaves[min1]->data + leaves[min2]->data;
		root->leftChild = leaves[min1];
		root->rightChild = leaves[min2];
		//將指向新樹的指針賦給leaves指針數組中min1位置
		leaves[min1] = root;
		// min2位置爲空
		leaves[min2] = NULL;
	}
	return root;
}

//根據權值獲取下標 
int getIndex(int weight){
	for(int i = 0 ;i<LENGTH;i++){
		if(weight == arr[i]){
			return i;
		}
	}
} 

//遞歸進行哈夫曼樹編碼,len是當前樹的層數
void huffmanCoding(TreeList& root, int len) {
	if (root == NULL) {
		return;
	}
	//若到葉子節點
	if (root->leftChild == NULL && root->rightChild == NULL) {
		//獲取該節點權值對應的字符下標 
		int index = getIndex(root->data);
		//保存該字符的哈夫曼編碼
		for (int i = 0; i < len; i++) {
			huffman[index].push_back(code[i] + '0');
		}
	}
	//否則繼續進行哈夫曼編碼的操作
	else {
		//左側分支都記爲零
		code[len] = 0;
		huffmanCoding(root->leftChild, len + 1);
		//右側分支都記爲一
		code[len] = 1;
		huffmanCoding(root->rightChild, len + 1);
	}
}

int main() {
	TreeList root = createTree(arr);
	huffmanCoding(root, 0);
	for (int i = 0; i < LENGTH; i++) {
		cout << alph[i] << "的哈夫曼編碼是 : " << huffman[i] << endl;
	}
	return 0;
}

4.5 運行結果


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章