哈夫曼树的创建

要了解哈夫曼树,可以先了解一下哈夫曼编码,假设我们有几个字母,他们的出现频率是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!=index0 ,为了找到第二个最小值,不和第一个重复。

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++;
	}
}

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

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

相关推荐
yszaygr21381 小时前
Verilog参数化游程编码RLE模块
算法
望易2 小时前
刚设计的大模型架构-双域耦合认知框架
算法·架构
复杂网络6 小时前
多个 Claude Code 与多个 Codex 协同工作:设计与实现方案
算法
apocelipes20 小时前
常用编程语言和库的正则表达式性能对比
c语言·c++·python·性能优化·golang·开发工具和环境
HjhIron21 小时前
面试常客:字符串算法从入门到进阶
算法·面试
吴佳浩1 天前
DeepSeek DSpark:Confidence-Scheduled Speculative Decoding 技术解析
人工智能·算法·deepseek
触底反弹1 天前
🧠 搞懂 Token,才算真正入门大模型——从分词原理到 Embedding 语义实战
javascript·人工智能·算法
vivo互联网技术1 天前
ICLR 2026 | 基于后验采样的图像恢复方法LearnIR:人脸去阴影、去雾
人工智能·算法·aigc
浮生望1 天前
JS字符串与回文算法:从包装类到双指针的面试进阶之路
javascript·算法
黄敬峰1 天前
面试必刷:从JS底层包装类到双指针,彻底搞懂字符串与回文算法
算法