哈夫曼树C语言实现学习笔记

哈夫曼树C语言实现学习笔记

  学习了一些关于哈夫曼树的博文,简单记一篇笔记。

1、基本概念
哈夫曼树:又称最优二叉树,是一种带权路径长度最短的二叉树。
路径:若在一棵树中存在着一个结点序列 k1,k2,……,kj, 使得 ki是ki+1 的双亲(1<=i<j),则称此结点序列是从 k1 到 kj 的路径。
路径长度:从 k1 到 kj 所经过的分支数称为这两点之间的路径长度,它等于路径上的结点数减1。
权:树中节点被赋予的一个有着某种意义的实数。
树的带权路径长度:树的带权路径长度定义为树中所有叶子结点的带权路径长度之和,公式为:

在这里插入图片描述
如下图中树的带权路径长度 WPL = 9 x 2 + 12 x 2 + 15 x 2 + 6 x 3 + 3 x 4 + 5 x 4 = 122。
在这里插入图片描述
2、构造过程
假设有n个权值,则构造出的哈夫曼树有n个叶子结点。 n个权值分别设为 w1、w2、…、wn,则哈夫曼树的构造规则为
(1)将w1、w2、…,wn看成是有n 棵树的森林(每棵树仅有一个结点)
(2)选出结点权值最小的两棵树合并,新树根节点权值为两子树权值之和,新树根节点替换之前两树结点。
(3)重复(2)直到只剩一棵树为止。
上图图解步骤如下
在这里插入图片描述
以最后的哈夫曼树左子树分支记0,右子树分支记1,将结点的路径上结点结合起来就是结点的哈夫曼编码:
A:00
B:01
C:100
D:1010
E:1011
F:11
注意:为了使得到的哈夫曼树的结构尽量唯一,通常规定生成的哈夫曼树中每个结点的左子树根结点的权小于等于右子树根结点的权。
3、代码实现
以下是哈夫曼树的相关实现:
tree.h

#ifndef __TREE_H__
#define __TREE_H__

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

#define MAXVALUE 1024     //最大权值
#define MAXBIT 1024       //哈夫曼编码最大长度
#define n  8              //叶子结点数目
#define m  (2*n-1)        //全部结点数目

typedef struct{
	char name[1024];
	int weight;
	int parent;
	int Lchild;
	int Rchild;
}Htree;

typedef struct{
	int bit[n];           //保存位串
	int start;            //编码起始位置
	char name[1024];
}Hcode;

void SelectTree(Htree tree[],int position,int *node1,int *node2); //选择两个权值最小的树结点 

void CreateTree(Htree tree[]);                                    //构造哈夫曼树

void CodeTree(Hcode code[],Htree tree[]);                         //开始编码 

void ShowTree(Htree tree[],Hcode code[]);                         //显示哈夫曼编码 

#endif

tree.c

#include "tree.h"

void SelectTree(Htree tree[],int position,int *node1,int *node2)
{
	*node1 = *node2 = 0;
	int min1,min2; 
	min1 = min2 = MAXVALUE;
	int i;
	for(i = 0; i < position; i++)
	{
		if(tree[i].parent == -1) 
		{
			if(tree[i].weight < min1) 
			{
				min2 = min1;
				min1 = tree[i].weight;
				*node2 = *node1; 
				*node1 = i; 
			}else if(tree[i].weight < min2){
				min2 = tree[i].weight;
				*node2 = i; 
			} 

		}
	}
}

void CreateTree(Htree tree[])
{
	int i;
	int node1,node2;
	node1 = node2 = 0;

	char name[1024]; 
	int now_weight; 
	for(i = 0; i < m; i++)
	{
		tree[i].weight = 0; 
		tree[i].parent = -1;
		tree[i].Lchild = -1;
		tree[i].Rchild = -1;
	}

	printf("一共有%d个人\n",n);

	for(i = 0; i < n; i++) 
	{
		printf("请输入姓名:");
		scanf("%s",name);
		printf("请输入成绩:");
		scanf("%d",&now_weight);
		strcpy(tree[i].name,name); 
		tree[i].weight = now_weight;
	}

	for(i = n; i < m; i++) 
	{
		SelectTree(tree,i,&node1,&node2); 
		tree[node1].parent = i;
		tree[node2].parent = i;
		tree[i].Lchild = node1;
		tree[i].Rchild = node2;
		tree[i].weight = tree[node1].weight + tree[node2].weight; 
	}
}

void CodeTree(Hcode code[],Htree tree[])
{
	int i;

	int parent_position,now_position;

	Hcode cd;        

	CreateTree(tree);

	for(i = 0; i < n; i++) 
	{
		cd.start = n;
		strcpy(cd.name,tree[i].name);
		now_position = i; 
		parent_position = tree[i].parent;
		while(parent_position != -1)
		{
			cd.start--;
			if(tree[parent_position].Lchild == now_position)
			{
				cd.bit[cd.start] = '0';
			}
			else
				cd.bit[cd.start] = '1';

			now_position = parent_position;   
			parent_position = tree[now_position].parent;
		} 

		code[i] = cd;                         	 

	} 
}

void ShowTree(Htree tree[],Hcode code[]) 
{
	int i,j;
	for(i = 0; i < n; i++)
	{
		printf("%s          ",code[i].name);
		for(j = code[i].start; j < n; j++)
			printf("%c ",code[i].bit[j]);

		printf("\n");
	} 
}

main.c

#include "tree.h"

int main()
{
	Htree tree[m];      //有m个位置的空树
	Hcode code[n];      //n个编码位置

	CodeTree(code,tree);//编码

	ShowTree(tree,code);//输出 

	return 0;
} 

makefile

main:main.c tree.c 
	gcc -o main main.c tree.c
clean:
	rm main
rebuild: clean main

下面是运行的效果截图
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值