哈夫曼树的创建和哈夫曼编码

哈夫曼树的构造

        数据类型的定义

typedef struct {
	ELMETYPE data;
	int weight;
	int parent;
	int leftchild;
	int rightchild;
}HuffNode;  //哈夫曼树结构体类型

        哈夫曼树的创建

int HuffTreeCreate(HuffNode* ht) {  
	int i, k, n, min1, min2, lnode, rnode;
//	i, k -->后面for循环需要用到的变量
//	n-->保存元素的个数
//	min1, min2 -->记录树中权值最小的值
//  lnode, rnode -->记录左右子树的编码 
	printf("请输入元素个数\n");
	scanf("%d", &n);
	printf("元素的个数为:%d\n", n);
	for (i = 1; i <= n; i++) { //输入叶子结点的权值
		getchar();  //用来吸收上一个scanf留下的\n
		printf("第%d个元素的 =>\n\t结点值:",i);
		scanf("%c", &ht[i].data);
		getchar();  //吸收上面的scanf留下的\n
		printf("\t权  重");
		scanf("%d", &ht[i].weight);
	}
	for (i = 1; i <= 2 * n - 1; i++) {  //初始化双亲,孩子数组
		ht[i].parent = -1;
		ht[i].leftchild = -1;
		ht[i].rightchild = -1;
	}
	for (i = n + 1; i <= 2 * n - 1; i++) { 
		min1 = min2 = 32767;  //先将变量赋为最大值
		lnode = rnode = 1;  //表示都从1下标开始
		for (k = 1; k <= i - 1; k++) { 
			if (ht[k].parent == -1) {  //没有父母的结点
				if (ht[k].weight < min1) {//小于min1,作为左子树
					min2 = min1; //原先的左子树变成右子树
					rnode = lnode; //记录该结点的下标
					min1 = ht[k].weight;
					lnode = k;
				}
				else if (ht[k].weight < min2) {
					min2 = ht[k].weight;
					rnode = k;
				}
			}
		}
		ht[i].weight = min1 + min2;  //将叶子结点的权值相加
		ht[i].leftchild = lnode;//记录左右孩子的下标
		ht[i].rightchild = rnode;
		ht[lnode].parent = i;//孩子结点记录母亲下标
		ht[rnode].parent = i;
	}
	printf("哈夫曼树已成功建立\n");
	return n;  //最后返回元素个数
}

        哈夫曼树的输出

void PrintfHuff(HuffNode* Hf, int index, int level) 
{                            //index:当前所处结点的索引,初始值为 2*n - 1 ; 
                             //level层级, 一般从第0层开始递增
	if (Hf[index].leftchild != -1 || Hf[index].rightchild != -1) 
	{ //这个if判断当前节点是否有子节点
		PrintfHuff(Hf, Hf[index].leftchild,level + 1); //遍历左子树
		if (level != 0) 
		{
			for(int i = 0; i < 4 * (level - 1); i++) 
			{
				printf("%s", " ");
			}
				printf("%s", " ----");
		}
		printf("o \n");
		PrintfHuff(Hf, Hf[index].rightchild, level+1);
	}
	else 
	{
		if (level != 0) 
		{
			for (int i = 0; i < 4 * (level - 1); i++)
			{
				printf("%s", " ");
			}
			printf("%s", " ---");
		}
		printf("%c \n", Hf[index].data);
	}
}

哈夫曼编码

        编码结构体

void Encoding(HuffNode ht[], HuffCode hcd[], int n) {
	HuffCode d;
	int i;
	int k;
	int ft;	//叶子结点的父亲
	int bg; //从叶子结点开始
	for (i = 1; i <= n; i++) 
	{
		d.start = n + 1;//即叶子结点合起来的结点
		bg = i;
		ft = ht[i].parent;
		while (ft != -1) 
		{
			if (ht[ft].leftchild == bg) 
			{
				d.code[--d.start] = '0';
			}
			else 
			{
				d.code[--d.start] = '1';
			}
			bg = ft;
			ft = ht[ft].parent;
		}
		hcd[i] = d;
	}
	printf("打印哈夫曼树:\n");
	for (i = 1; i <= n; i++) 
	{
		printf("%c:", ht[i].data);
		for (k = hcd[i].start; k <= n; k++) 
		{
			printf("%c", hcd[i].code[k]);
		}
		printf("\n");
	}
}

全部代码和主函数测试

#include<stdio.h>
#include<malloc.h>

#define MAXSIZE 30

typedef char ELMETYPE;

typedef struct {
	ELMETYPE data;
	int weight;
	int parent;
	int leftchild;
	int rightchild;
}HuffNode;

typedef struct {
	ELMETYPE code[MAXSIZE];
	int start;//编码的起始位置
}HuffCode;

int HuffTreeCreate(HuffNode* ht) {
	int i, k, n, min1, min2, lnode, rnode;
//	i, k -->后面for循环需要用到的变量
//	n-->保存元素的个数
//	min1, min2 -->记录树中权值最小的值
//  lnode, rnode -->记录左右子树的编码 
	printf("请输入元素个数\n");
	scanf("%d", &n);
	printf("元素的个数为:%d\n", n);
	for (i = 1; i <= n; i++) { //输入叶子结点的权值
		getchar();  
		printf("第%d个元素的 =>\n\t结点值:",i);
		scanf("%c", &ht[i].data);
		getchar();  
		printf("\t权  重:");
		scanf("%d", &ht[i].weight);
	}
	for (i = 1; i <= 2 * n - 1; i++) {  //初始化双亲,孩子数组
		ht[i].parent = -1;
		ht[i].leftchild = -1;
		ht[i].rightchild = -1;
	}
	for (i = n + 1; i <= 2 * n - 1; i++) { 
		min1 = min2 = 32767;  //先将变量赋为最大值
		lnode = rnode = 1;  //表示都从1下标开始
		for (k = 1; k <= i - 1; k++) { 
			if (ht[k].parent == -1) {  //没有父母的结点
				if (ht[k].weight < min1) {//小于min1,作为左子树
					min2 = min1; //原先的左子树变成右子树
					rnode = lnode; //记录该结点的下标
					min1 = ht[k].weight;
					lnode = k;
				}
				else if (ht[k].weight < min2) {
					min2 = ht[k].weight;
					rnode = k;
				}
			}
		}
		ht[i].weight = min1 + min2;  //将叶子结点的权值相加
		ht[i].leftchild = lnode;//记录左右孩子的下标
		ht[i].rightchild = rnode;
		ht[lnode].parent = i;//孩子结点记录母亲下标
		ht[rnode].parent = i;
	}
	printf("哈夫曼树已成功建立\n");
	return n;
}

void PrintfHuff(HuffNode* Hf, int index, int level) 
{ 							//index:初始值为 2*n - 1 ; level层级, 一般从第0层开始 
	if (Hf[index].leftchild != -1 || Hf[index].rightchild != -1) 
	{ 
		PrintfHuff(Hf, Hf[index].leftchild, level + 1);
		if (level != 0) 
		{
			for(int i = 0; i < 4 * (level - 1); i++) 
			{
				printf("%s", " ");
			}
				printf("%s", " ----");
		}
		printf("o \n");
		PrintfHuff(Hf, Hf[index].rightchild, level+1);
	}
	else 
	{
		if (level != 0) 
		{
			for (int i = 0; i < 4 * (level - 1); i++)
			{
				printf("%s", " ");
			}
			printf("%s", " ---");
		}
		printf("%c \n", Hf[index].data);
	}
}

void Encoding(HuffNode ht[], HuffCode hcd[], int n) {
	HuffCode d;
	int i;
	int k;
	int ft;	//叶子结点的父亲
	int bg; //从叶子结点开始
	for (i = 1; i <= n; i++) 
	{
		d.start = n + 1;//即叶子结点合起来的结点
		bg = i;
		ft = ht[i].parent;
		while (ft != -1) 
		{
			if (ht[ft].leftchild == bg) 
			{
				d.code[--d.start] = '0';
			}
			else 
			{
				d.code[--d.start] = '1';
			}
			bg = ft;
			ft = ht[ft].parent;
		}
		hcd[i] = d;
	}
	printf("打印哈夫曼树:\n");
	for (i = 1; i <= n; i++) 
	{
		printf("%c:", ht[i].data);
		for (k = hcd[i].start; k <= n; k++) 
		{
			printf("%c", hcd[i].code[k]);
		}
		printf("\n");
	}
}
int main()
{
	HuffNode ht[MAXSIZE]; 
	HuffCode hcd[MAXSIZE]; 
	int n = HuffTreeCreate(ht);
	PrintfHuff(ht, 2*n-1, 0); 
	Encoding(ht, hcd, n);
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值