哈夫曼树的创建

要了解哈夫曼树,可以先了解一下哈夫曼编码,假设我们有几个字母,他们的出现频率是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++;
	}
}

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

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

相关推荐
CHANG_THE_WORLD7 分钟前
金字塔降低采样
算法·金字塔采样
我爱学嵌入式8 分钟前
C语言第 9 天学习笔记:数组(二维数组与字符数组)
c语言·笔记·学习
不知天地为何吴女士2 小时前
Day32| 509. 斐波那契数、70. 爬楼梯、746. 使用最小花费爬楼梯
算法
小坏坏的大世界2 小时前
C++ STL常用容器总结(vector, deque, list, map, set)
c++·算法
励志要当大牛的小白菜5 小时前
ART配对软件使用
开发语言·c++·qt·算法
qq_513970445 小时前
力扣 hot100 Day56
算法·leetcode
PAK向日葵6 小时前
【算法导论】如何攻克一道Hard难度的LeetCode题?以「寻找两个正序数组的中位数」为例
c++·算法·面试
爱装代码的小瓶子7 小时前
数据结构之队列(C语言)
c语言·开发语言·数据结构
爱喝矿泉水的猛男8 小时前
非定长滑动窗口(持续更新)
算法·leetcode·职场和发展
YuTaoShao8 小时前
【LeetCode 热题 100】131. 分割回文串——回溯
java·算法·leetcode·深度优先