哈夫曼树是最优二叉树,它的特点是所有叶子节点上的权重之和最小的树。构建哈夫曼树的过程如下:
构建哈夫曼树的过程很简单,但是需要用到另外一个辅助数据结构:有序链表。我们将实现一个有序链表存放构建哈夫曼树的节点:
#include "typedef.h"
//表数据结构
typedef struct s_list
{
	//权重
	int weights;
	//数据项
	void *data;
	//头节点
	struct s_list *next;
} s_list;
//按升序插入链表
bool list_insert(s_list *list, int weights, void *data)
{
	if (list == null || data == null)
	{
		return false;
	}
	//申请新节点内存
	s_list *p_new = (s_list *) malloc(sizeof(s_list));
	p_new->weights = weights;
	p_new->data = data;
	p_new->next = null;
	//第一个节点
	if (list->next == null)
	{
		list->next = p_new;
		return true;
	}
	//按顺序插入节点
	s_list *p = list;
	while (p->next != null)
	{
		//只在权重小于下一个节点时插入
		if (p_new->weights <= p->next->weights)
		{
			//插入新节点
			p_new->next = p->next;
			p->next = p_new;
			return true;
		}
		p = p->next;
	}
	p->next = p_new;
	return true;
}
//删除链表中指定元素节点
bool list_delete(s_list *list, void *data)
{
	if (list == null)
	{
		return false;
	}
	s_list *p = list;
	while (p->next != null)
	{
		//找到数据相同的节点
		if (p->next->data == data)
		{
			//删除节点
			s_list *p_del = p->next;
			p->next = p_del->next;
			//释放内存
			free(p_del);
			return true;
		}
		p = p->next;
	}
	return false;
}
再来实现一个哈夫曼树:
//赫夫曼节点
typedef struct s_node
{
	//数据指针
	void *data;
	//父节点
	struct s_node *parent;
	//左孩子节点
	struct s_node *left_child;
	//右孩子节点
	struct s_node *right_child;
} s_node;
//赫夫曼数据结构
typedef struct s_tree
{
	//根节点
	s_node *root;
	//访问函数指针
	void (*visit_node)();
	//释放内存函数指针
	void (*free_node)();
} s_tree;
//由一个有序链表构建赫夫曼树
bool tree_create(s_tree *tree, s_list *list)
{
	if (tree == null)
	{
		return false;
	}
	if (list == null)
	{
		return false;
	}
	if (list->next == null)
	{
		return false;
	}
	//当有序链表中前两个节点不为空时
	while (list->next != null && list->next->next != null)
	{
		//取出有序链表中第一个节点
		s_list *p0 = list->next;
		//取出有序链表中第二个节点
		s_list *p1 = list->next->next;
		//取得树节点,权重小的为左节点,权重大的为右节点,
		s_node *n_left = (s_node *) p0->data;
		s_node *n_right = (s_node *) p1->data;
		//权重相同时无子树的为左节点
		if (p0->weights == p1->weights)
		{
			s_node *n_temp = n_left;
			n_left = n_right;
			n_right = n_temp;
		}
		//申请新节点内存
		s_node *n_node = (s_node *) malloc(sizeof(s_node));
		//权重相加
		int weights = p0->weights + p1->weights;
		//删除有序链表中的前两个节点
		list_delete(list, p0->data);
		list_delete(list, p1->data);
		//构建新节点
		n_node->data = null;
		n_node->left_child = n_left;
		n_node->right_child = n_right;
		n_left->parent = n_node;
		n_right->parent = n_node;
		//将新节点插入有序链表
		list_insert(list, weights, n_node);
	}
	//经由上面处理后,有序链表中只留下一个节点
	s_list *p = list->next;
	//取得二叉树的根节点
	s_node *n_root = (s_node *) p->data;
	//设定二叉树的根节点
	tree->root = n_root;
	return true;
}
//前序遍历
void tree_preamble_visit(s_tree *tree, s_node *node)
{
	if (tree == null)
	{
		return;
	}
	if (tree->root == null)
	{
		return;
	}
	if (node == null)
	{
		return;
	}
	//中
	tree->visit_node(node->data);
	//左
	tree_preamble_visit(tree, node->left_child);
	//右
	tree_preamble_visit(tree, node->right_child);
}
最后来实现两个例子,测试我们的哈夫曼树:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "tree.h"
#include "list.h"
//删除整数函数
void free_int(int *i)
{
	if (i != null)
	{
		free(i);
	}
}
//访问整数函数
void visit_int(int *i)
{
	if (i != null)
	{
		printf("%d ", *i);
	}
}
void sample_A()
{
	s_list *list = (s_list *) malloc(sizeof(s_list));
	list->weights = 0;
	list->data = null;
	list->next = null;
	s_tree tree;
	tree_init(&tree, &visit_int, &free_int);
	int *t0 = (int *) malloc(sizeof(int));
	int *t1 = (int *) malloc(sizeof(int));
	int *t2 = (int *) malloc(sizeof(int));
	int *t3 = (int *) malloc(sizeof(int));
	int *t4 = (int *) malloc(sizeof(int));
	int *t5 = (int *) malloc(sizeof(int));
	int *t6 = (int *) malloc(sizeof(int));
	int *t7 = (int *) malloc(sizeof(int));
	int *t8 = (int *) malloc(sizeof(int));
	*t0 = 0;
	*t1 = 1;
	*t2 = 2;
	*t3 = 3;
	*t4 = 4;
	*t5 = 5;
	*t6 = 6;
	*t7 = 7;
	*t8 = 8;
	s_node *n0 = (s_node *) malloc(sizeof(s_node));
	s_node *n1 = (s_node *) malloc(sizeof(s_node));
	s_node *n2 = (s_node *) malloc(sizeof(s_node));
	s_node *n3 = (s_node *) malloc(sizeof(s_node));
	s_node *n4 = (s_node *) malloc(sizeof(s_node));
	s_node *n5 = (s_node *) malloc(sizeof(s_node));
	s_node *n6 = (s_node *) malloc(sizeof(s_node));
	s_node *n7 = (s_node *) malloc(sizeof(s_node));
	s_node *n8 = (s_node *) malloc(sizeof(s_node));
	tree_init_node(n0, t0);
	tree_init_node(n1, t1);
	tree_init_node(n2, t2);
	tree_init_node(n3, t3);
	tree_init_node(n4, t4);
	tree_init_node(n5, t5);
	tree_init_node(n6, t6);
	tree_init_node(n7, t7);
	tree_init_node(n8, t8);
	list_insert(list, 0, n0);
	list_insert(list, 1, n1);
	list_insert(list, 2, n2);
	list_insert(list, 3, n3);
	list_insert(list, 4, n4);
	list_insert(list, 5, n5);
	list_insert(list, 6, n6);
	list_insert(list, 7, n7);
	list_insert(list, 8, n8);
	tree_create(&tree, list);
	//前序遍历
	tree_preamble_visit(&tree, tree.root);
	printf("\n");
	//销毁树
	tree_destroy(&tree);
	free(list);
}
void sample_B()
{
	s_list *list = (s_list *) malloc(sizeof(s_list));
	list->weights = 0;
	list->data = null;
	list->next = null;
	s_tree tree;
	tree_init(&tree, &visit_int, &free_int);
	int *t0 = (int *) malloc(sizeof(char));
	int *t1 = (int *) malloc(sizeof(char));
	int *t2 = (int *) malloc(sizeof(char));
	int *t3 = (int *) malloc(sizeof(char));
	int *t4 = (int *) malloc(sizeof(char));
	int *t5 = (int *) malloc(sizeof(char));
	int *t6 = (int *) malloc(sizeof(char));
	int *t7 = (int *) malloc(sizeof(char));
	*t0 = 5;
	*t1 = 29;
	*t2 = 7;
	*t3 = 8;
	*t4 = 14;
	*t5 = 23;
	*t6 = 3;
	*t7 = 11;
	s_node *n0 = (s_node *) malloc(sizeof(s_node));
	s_node *n1 = (s_node *) malloc(sizeof(s_node));
	s_node *n2 = (s_node *) malloc(sizeof(s_node));
	s_node *n3 = (s_node *) malloc(sizeof(s_node));
	s_node *n4 = (s_node *) malloc(sizeof(s_node));
	s_node *n5 = (s_node *) malloc(sizeof(s_node));
	s_node *n6 = (s_node *) malloc(sizeof(s_node));
	s_node *n7 = (s_node *) malloc(sizeof(s_node));
	tree_init_node(n0, t0);
	tree_init_node(n1, t1);
	tree_init_node(n2, t2);
	tree_init_node(n3, t3);
	tree_init_node(n4, t4);
	tree_init_node(n5, t5);
	tree_init_node(n6, t6);
	tree_init_node(n7, t7);
	list_insert(list, 5, n0);
	list_insert(list, 29, n1);
	list_insert(list, 7, n2);
	list_insert(list, 8, n3);
	list_insert(list, 14, n4);
	list_insert(list, 23, n5);
	list_insert(list, 3, n6);
	list_insert(list, 11, n7);
	tree_create(&tree, list);
	//前序遍历
	tree_preamble_visit(&tree, tree.root);
	printf("\n");
	//销毁树
	tree_destroy(&tree);
	free(list);
}
int main(int argc, char **args)
{
	sample_A();
	sample_B();
	return 0;
}
运行结果:
7 8 4 5 6 3 0 1 2 8 11 23 29 14 7 3 5
这两个哈夫曼树如下:


本例代码:
code path chapter.05/e.g.5.5/ https https://github.com/magicworldos/datastructure.git git git@github.com:magicworldos/datastructure.git subverion https://github.com/magicworldos/datastructure
Copyright © 2015-2023 问渠网 辽ICP备15013245号