哈夫曼树(最优二叉树)纯C实现

哈夫曼树的构造规则为:
假设有n个权值,则构造出的哈夫曼树有n个叶子结点。 n个权值分别设为 w1、w2、…、wn
(1) 将w1、w2、…,wn看成是有n 棵树的森林(每棵树仅有一个结点);
(2) 在森林中选出两个根结点的权值最小的树合并,作为一棵新树的左、右子树,且新树的根结点权值为其左、右子树根结点权值之和;
(3)从森林中删除选取的两棵树,并将新树加入森林;
(4)重复(2)、(3)步,直到森林中只剩一棵树为止,该树即为所求得的哈夫曼树。

huffman_tree.c
/************************************************************************/
/* 哈夫曼树(最优二叉树)                                                 */
/* 对给定的一串字符串按字符出现的频率对其进行编、解码                   */
/* ziven	20131024                                                    */
/************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "stack.h"
#include "list.h"

#define	MAX		500

typedef struct _huff_node huffman_node_t;
typedef struct _huff_node *huffman_tree_t;
typedef struct _node_info node_info_t;

struct _node_info
{
	char c;
	int  wei;
	char code[20];
	huffman_node_t *node;
};

struct _huff_node
{
	node_info_t       *node_info;
	struct _huff_node *parent;
	struct _huff_node *lchild;
	struct _huff_node *rchild;
};


typedef struct
{
	node_info_t info[MAX];
	int		cout;
}node_t;

void huffman_count(char *s , int len, node_t *node)
{
	int i = 0, j = 0;

	node->cout = 0;

	for (i = 0; i < len; i++)
	{
		for (j = 0; j < node->cout; j++)
		{
			if (s[i] == node->info[j].c)
			{
				node->info[j].wei++;
				break;
			}
		}
		if (j == node->cout)
		{
			node->info[node->cout].c = s[i];
			node->info[node->cout].wei = 1;
			memset(node->info[node->cout].code, 0, sizeof(node->info[node->cout].code));
			node->info[node->cout].node = NULL;
			
			node->cout++;
		}
	}
}

int huffman_cmp(huffman_node_t *n1, huffman_node_t *n2)
{
	if (n1->node_info->wei > n2->node_info->wei)
	{
		return 1;
	}
	else if (n1->node_info->wei == n2->node_info->wei)
	{
		return 0;
	}
	else
	{
		return -1;
	}
}


void huffman_create(node_t *node, huffman_tree_t *tree)
{
	int i = 0;

	huffman_node_t *huffman_node = NULL;
	huffman_node_t *node1 = NULL, *node2 = NULL;

	list_t *list = list_new();
	list->cmp = (list_cmp_f)huffman_cmp;

	for (i = 0; i < node->cout; i++)
	{
		huffman_node = (huffman_node_t *)malloc(sizeof(huffman_node_t));
		huffman_node->node_info = &node->info[i];
		huffman_node->lchild = NULL;
		huffman_node->rchild = NULL;
		huffman_node->parent = NULL;

		node->info[i].node = huffman_node;

		listnode_add_sort(list, (void *)huffman_node);
	}
	
	while (list->count != 1)
	{
		node1 = (huffman_node_t *)(list->head->data);
		node2 = (huffman_node_t *)(list->head->next->data);

		huffman_node = (huffman_node_t *)malloc(sizeof(huffman_node_t));

		huffman_node->node_info = (node_info_t *)malloc(sizeof(node_info_t));
		memset(huffman_node->node_info, 0, sizeof(node_info_t));
		huffman_node->lchild = node1;
		huffman_node->rchild = node2;
		huffman_node->parent = NULL;
		huffman_node->node_info->wei = node1->node_info->wei + node2->node_info->wei;

		node1->parent = huffman_node;
		node2->parent = huffman_node;
		
		listnode_delete(list, (void *)node1);
		listnode_delete(list, (void *)node2);

		listnode_add_sort(list, (void *)huffman_node);
	}

	*tree = (huffman_tree_t)(list->head->data);
}

void huffman_code(huffman_tree_t tree)
{
	if (tree == NULL)
	{
		return;
	}
	if (tree->parent != NULL)
	{
		strcpy(tree->node_info->code, tree->parent->node_info->code);
		if (tree->parent->lchild == tree)
		{
			tree->node_info->code[strlen(tree->node_info->code)] = '1';
		}
		else
		{
			tree->node_info->code[strlen(tree->node_info->code)] = '0';
		}
	}

	huffman_code(tree->lchild);
	huffman_code(tree->rchild);
}

void huffman_recode(node_t node, char *s, int len)
{
	int i = 0;
	int j = 0;

	for (i = 0; i < len;)
	{
		for (j = 0; j < node.cout; j++)
		{
			if (!strncmp(node.info[j].code, s, strlen(node.info[j].code)))
			{
				s += strlen(node.info[j].code);
				printf("%c ", node.info[j].c);
				i += strlen(node.info[j].code);
				break;
			}
		}

		if (j == node.cout)
		{
			printf("解析失败!\n");
			break;
		}
	}
}

void huffman_pre_reverse(huffman_tree_t tree)
{
	if (tree == NULL)
	{
		return;
	}

	printf("%c(%d) ", tree->node_info->c, tree->node_info->wei);
	huffman_pre_reverse(tree->lchild);
	huffman_pre_reverse(tree->rchild);
}

void huffman_test()
{
	node_t node;
	huffman_tree_t tree;
	int i = 0;

	char s[MAX];
	memset(s, 0, sizeof(s));
	printf("输入字符串:\n");
	gets(s);

	huffman_count(s, strlen(s), &node);
	for (i = 0; i < node.cout; i++)
	{
		printf("%c 出现次数为:%d \n", node.info[i].c, node.info[i].wei);
	}

	huffman_create(&node, &tree);
	
	//huffman_pre_reverse(tree);printf("\n");

	huffman_code(tree);
	for (i = 0; i < node.cout; i++)
	{
		printf("%c 的哈夫曼编码为:%s \n", node.info[i].c, node.info[i].code);
	}

	printf("输入1、0组成的字符串:\n");
	gets(s);
	huffman_recode(node, s, strlen(s));
}
list.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "list.h"

list_t *list_new()
{
	list_t *node;

	node = (list_t *)malloc(sizeof(list_t));

	memset(node, 0, sizeof(list_t));

	return node;
}

listnode_t *listnode_new()
{
	listnode_t *node;

	node = (listnode_t *)malloc(sizeof(listnode_t));

	if (node == NULL)
	{
		return NULL;
	}

	memset(node, 0, sizeof(listnode_t));

	return node;
}

listnode_t *listnode_add(list_t *list, void *v)
{
	listnode_t *node = listnode_new();

	if (node == NULL)
	{
		return NULL;
	}

	node->prev = list->tail;
	node->data = v;

	if (list->head == NULL)
	{
		list->head = node;
	}
	else
	{
		list->tail->next = node;
	}

	list->tail = node;

	list->count++;

	return node;
}

listnode_t *listnode_add_sort(list_t *list, void *v)
{
	listnode_t *n;
	listnode_t *node = listnode_new();

	if (node == NULL)
	{
		return NULL;
	}

	node->data = v;

	if (list->cmp)
	{
		for (n = list->head; n; n = n->next)
		{
			if ((*list->cmp)(v, n->data) < 0)
			{
				node->next = n;
				node->prev = n->prev;

				if (n->prev)
				{
					n->prev->next = node;
				}
				else
				{
					list->head = node;
				}

				n->prev = node;
				list->count++;

				return node;
			}
		}
	}

	node->prev = list->tail;

	if (list->tail)
	{
		list->tail->next = node;
	}
	else
	{
		list->head = node;
	}

	list->tail = node;
	list->count++;

	return node;
}

void listnode_delete (list_t *list, void *val)
{
	listnode_t *node;

	for (node = list->head; node; node = node->next) 
	{
		if (node->data == val) 
		{
			if (node->prev)
				node->prev->next = node->next;
			else
				list->head = node->next;

			if (node->next)
				node->next->prev = node->prev;
			else
				list->tail = node->prev;

			list->count--;
			free(node);
			return;
		}
	}
}

运行结果:


  • 1
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值