学弟讲算法·哈夫曼树与哈夫曼编码

一、 实验目的

通过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 运行结果


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