【水 C/C++ 数据结构】哈夫曼编码 2019_12_19

逻辑结构

树结构

物理存储结构

数组

算法图解

在这里插入图片描述

代码

哈夫曼树结构体

typedef struct
{
	int weight;
	int lchild, rchild, parent;
}HTNode, *HuffmanTree;
//*HuffmanTree 是指向 HTNode 结构体 的指针;
//malloc分配数组内存,存储最优二叉树

typedef char * * HuffmanCode;
//char** 别名 HuffmanCode ⇒ 视为 char[][]
//malloc分配数组内存,存储最优二叉树编码表(哈夫曼码表)

哈夫曼编码

/*
参数列表:
	存储HuffmanTree类型元素的数组首地址(指针存储首地址) HT
	存储HuffmanCode类型元素的数组首地址(指针存储首地址)  HC
	存储int类型元素的数组首地址(指针存储首地址) w
	叶子节点个数 n
*/
void HuffmanCoding(HuffmanTree &HT, HuffmanCode &HC, int * w, int n) {
	if (n <= 1)
		return;
	//0.定义
	int m = 2 * n - 1; //m 为 总节点数
	HT = (HuffmanTree)malloc((m + 1) * sizeof(HTNode));	//赋值HT

	//1.初始化 哈夫曼树状态
	HuffmanTree p = HT;
	*p = { 1000,0,0,0 };
	p = HT + 1;
	int i = 1;
	for (;i <= n; ++i, ++p, ++w)
		*p = { *w,0,0,0 };
	for(;i<=m;++i,++p)
		*p = { 0,0,0,0 };
	//2.演变最终 哈夫曼树状态
	for (i = n + 1; i <= m; ++i) {			//BUG1 现象:最后一个节点的 parent == -8000+ ,最后一个节点未初始化。解决:调整 p 大小
		//定义Select所需参数				//BUG2 现象:最后两个节点的 parent 与 w 有误,之前的节点全部正确。解决:使用 未被使用的0号节点,存储大权值1000
		int s1 = 0;
		int s2 = 0;
		Select(HT, i-1, s1, s2);
		HT[s1].parent = i; HT[s2].parent = i;
		HT[i].lchild = s1; HT[i].rchild = s2;
		HT[i].weight = HT[s1].weight + HT[s2].weight;
	}
	//3.从叶子 --> 根 逆向求解每个字符的哈夫曼编码
	//HC = (HuffmanCode)malloc((n + 1) * sizeof(char *));
	HC = (HuffmanCode)malloc((n + 1) * sizeof(char *));
	char * cd = (char *)malloc(n * sizeof(char));
	cd[n - 1] = '\0';
	for (int i = 1; i <= n; ++i) {
		int start = n - 1;
		int c,f = 0;
		c=i;
		f = HT[i].parent;
		for (; f != 0; ) {
			if (HT[f].lchild == c)
				cd[--start] = '0';
			else
				cd[--start] = '1';
			HC[i] = (char *)malloc((n - start) * sizeof(char));
			strcpy(HC[i], &cd[start]);
			c = f;
			f = HT[f].parent;
		}
	}
	free(cd);							//BUG3 现象:free(cd)异常.解决:cd内存的释放,应在HC字符编码全部完成后。
}

选择两最小权值

//在已知节点中,挑选 parent==0 且 权值最小的两个节点
void Select(HuffmanTree &HT, int range, int &s1, int &s2) {
	//得出s1
	for (int i = 1; i <= range; i++) {
		//如果当前节点parent不为0,则跳过此次循环
		if (HT[i].parent != 0)
			continue;
		if (HT[i].weight <= HT[s1].weight)
			s1 = i;
	}
	//得出s2
	for (int i = 1; i <= range; i++) {
		//如果当前节点parent不为0,则跳过此次循环
		if (i == s1)
			continue;
		if (HT[i].parent != 0)
			continue;
		if (HT[i].weight <= HT[s2].weight)
			s2 = i;
	}
}

主函数测试

int main() {
	//0.定义=声明+赋值 HuffmanCoding 函数所需 参数
	char c[] = { 'a','b','c','d' };
	int w[] = {7,5,2,4};				//权值数组
	//0.只声明
	HuffmanTree HT;
	HuffmanCode HC;
	//1.调用 HuffmanCoding
	HuffmanCoding(HT, HC, w, N);

	//2.打印 HC 哈夫曼编码
	for (int i = 1; i <= sizeof(HC); i++)
	{
		cout << c[i - 1] << ":" << HC[i] << endl;					//BUG4 现象:HC[i]访问异常.解决:HC[0]未被使用,i 从 1 -> sizeof(HC)。
	}

	return 0;
}

注:为什么,不从 0 开始使用,可能是书上为了更贴合 人类思维,从1开始。

参考资料

内容网址
ASCIIhttps://baike.baidu.com/item/ASCII/309296?fr=aladdin
char * & char **https://blog.csdn.net/crazyeden/article/details/81124414
参数传递方式*3https://blog.csdn.net/weibo1230123/article/details/75541862
残缺·哈夫曼编码实现https://blog.csdn.net/weixin_42261396/article/details/85174621
struct {} Node,*PNode;https://bbs.csdn.net/topics/270018485
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值