哈夫曼树的创建

要了解哈夫曼树,可以先了解一下哈夫曼编码,假设我们有几个字母,他们的出现频率是A: 1 B: 2 C: 3 D: 4 E: 5 F: 6 G: 7。那么如果想要压缩数据的同时让访问更加快捷,就要让频率高的字母离根节点比较进,容易访问,频率低的离根节点远。

所以,构建哈夫曼树的步骤,是一直找最小频率的两个节点,组成一个树,拿上面的例子:

A B的频率最低,所以第一步先把AB当作左右孩子构建树,现在AB相当于一个节点,权值为3。

再次比较,最小的权值是3,3(一个是AB节点的根,一个是C节点)接着构成树。

现在最小的是权值为4,5节点,相当于4,5节点构成树,但此时上面的树仍然存在。

这里直接放最后树的结果了:

现在梳理一下步骤:

1.先找到最小的两个点,构建他们的根节点。

2.把这两个点从节点中去除,把他们的根节点加入进来。

3.循环这个过程直到只有一个节点。

首先我们要写一个寻找权值最小并且构建根节点的函数,这里我们用一个数组用来存放普通的树节点,根据数学推导,(会增加 n-1 个节点,因为最开始是2个节点增加一个)哈夫曼树最后是 2n-1 个节点,这里先创建n个节点,后面可以realloc扩容。

哈夫曼树的创建先创建 n 的节点的空间,给 n 个节点赋值,也就是初始值。这里的parent是告诉所有节点都在可比较的范围内,如果parent为1,那么说明节点已经参与构建树,也就是再寻找最小值时跳过。

cpp 复制代码
typedef struct HuffmanTree {
	TreeNode* array;
	int length;
}HuffmanTree;

HuffmanTree* HuffmanTreeInit(int length,int* data,HuffmanTree* H) {
	H = (HuffmanTree*)malloc(sizeof(HuffmanTree));
	H->array = (TreeNode*)malloc(sizeof(TreeNode) * length);
	H->length = length;
	for (int i = 0; i < length; i++) {
		H->array[i].val = data[i];
		H->array[i].lchild = NULL;
		H->array[i].rchild = NULL;
		H->array[i].parent = 0;
	}
	return H;
}

接着是寻找最小的两个值的节点,index数组存放的是两个节点的序号,最后返回,前后两个for循环一样,只不过要注意第二个for循环 && j!=index[0] ,为了找到第二个最小值,不和第一个重复。

cpp 复制代码
int* FindTwoMin(HuffmanTree* H) {
	int* index = (int*)malloc(sizeof(int) * 2);
	int min1 = 1000;
	int min2 = 1000;
	for (int i = 0; i < H->length; i++) {
		if (H->array[i].parent == 0) {
			if (H->array[i].val < min1) {
				min1 = H->array[i].val;
				index[0] = i;
			}
		}
	}
	for (int j = 0; j < H->length; j++) {
		if (H->array[j].parent == 0) {
			if (H->array[j].val < min2 && j!=index[0]) {
				min2 = H->array[j].val;
				index[1] = j;
			}
		}
	}
	return index;
}

最后就是构建哈夫曼树:

cpp 复制代码
void CreatHuffmanTree(HuffmanTree* H) {
	int i = H->length,count=H->length;
	while( i < count * 2 - 1) {

        先找到最小的两个节点的序号
		int* index = FindTwoMin(H);

        创建最小两个节点的根
		H->array = (TreeNode*)realloc(H->array,sizeof(TreeNode) * (i + 1));
		H->array[i].val = H->array[index[0]].val + H->array[index[1]].val;
		H->array[i].parent = 0;
		H->array[i].lchild = &H->array[index[0]];
		H->array[i].rchild = &H->array[index[1]];

        把parent置为非0,表示已经构建
		H->array[index[0]].parent = i;
		H->array[index[1]].parent = i;

        树的容量值更新
		H->length++;
		i++;
	}
}

最后是主函数和结果,最后用先序遍历打印了一下哈夫曼树,符合上面哈夫曼树的图。

这就是文章的全部内容了,希望对你有所帮助,如有错误欢迎评论。

相关推荐
涛ing22 分钟前
32. C 语言 安全函数( _s 尾缀)
linux·c语言·c++·vscode·算法·安全·vim
xrgs_shz1 小时前
MATLAB的数据类型和各类数据类型转化示例
开发语言·数据结构·matlab
独正己身1 小时前
代码随想录day4
数据结构·c++·算法
厂太_STAB_丝针2 小时前
【自学嵌入式(8)天气时钟:天气模块开发、主函数编写】
c语言·单片机·嵌入式硬件
利刃大大4 小时前
【回溯+剪枝】找出所有子集的异或总和再求和 && 全排列Ⅱ
c++·算法·深度优先·剪枝
charlie1145141914 小时前
从0开始使用面对对象C语言搭建一个基于OLED的图形显示框架(协议层封装)
c语言·驱动开发·单片机·学习·教程·oled
*TQK*4 小时前
ZZNUOJ(C/C++)基础练习1041——1050(详解版)
c语言·c++·编程知识点
Rachela_z5 小时前
代码随想录算法训练营第十四天| 二叉树2
数据结构·算法
细嗅蔷薇@5 小时前
迪杰斯特拉(Dijkstra)算法
数据结构·算法
追求源于热爱!5 小时前
记5(一元逻辑回归+线性分类器+多元逻辑回归
算法·机器学习·逻辑回归