xdoj huffman哈夫曼编码

本文采用的此方法的主体部分是利用结构体数组,构造一棵可以从叶子节点回溯到根节点,以及可以从根节点到达叶子节点的哈夫曼树,有了这个树之后无论是求权值还是哈夫曼编码都会比较容易。

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
typedef struct HTNode
{
	int weight;
	int parent, lchild, rchild;
}HTNode, * HuffmanTree;

void Select(HuffmanTree HT, int n, int* a, int* b);

int main()
{
	int n, i, j, m, a, b, WPL = 0;
	int w[100];//用w来先存贮权重
	HuffmanTree HT, p;
	scanf("%d", &n);
	for (i = 0; i < n; i++)
	{
		scanf("%d", &w[i]);
	}
	m = 2 * n - 1;//根据二叉树的性质,有n个叶子就有2n-1个节点
	HT = (HuffmanTree)malloc((m+1) * sizeof(HTNode));//动态分配空间,直接给个大的结构体数组也可以
	for (p = HT + 1, i = 1; i <= n; i++, p++)//从HT[1]开始赋值,从[0]也可以
	{
		HT[i] = { w[i - 1], 0, 0, 0};
	}//将叶子节点的权重赋给前n项
	for (; i <= m; ++i, ++p) 
		*p = { 0, 0, 0, 0 };//对叶子节点后面的节点做初始化
	for (i = n + 1; i <= m; i++)
	{
		Select(HT, i - 1, &a, &b);
		HT[i].weight = HT[a].weight + HT[b].weight;//双亲节点权值
		HT[i].lchild = a;
		HT[i].rchild = b;//可以不记录孩子节点
		HT[a].parent = i;
		HT[b].parent = i;
	}
	for (i = 1; i <= n; i++)
	{
		int len = 0;
		int p = i;
		while (HT[p].parent != 0)//到根节点的时候len就是此叶子的路径长
		{
			p = HT[p].parent;
			len++;
		}
		WPL += len * HT[i].weight;
	}
	printf("%d", WPL);
	return 0;
}

void Select(HuffmanTree HT, int n, int* a, int* b)
{
	int i;
	int min1 = 10000, min2 = 10000;//找最小的一开始不好比较,直接取一个较大值
	for (i = 1; i <= n; i++)
	{
		if (HT[i].weight < min1 && HT[i].parent == 0)//已经被用在哈夫曼树里的节点双亲节点不为零
		{
			min1 = HT[i].weight;
			*a = i;
		}
	}
	for (i = 1; i <= n; i++)
	{
		if (HT[i].weight <= min2 && HT[i].parent == 0 && i != *a)//不能让min1 == min2
		{
			min2 = HT[i].weight;
			*b = i;
		}
	}
}

此题也可以利用一些数学规律,比方WPL是每次两个最小数之和的和,利用数组和排序求解。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值