一、 實驗目的
通過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 運行結果