赫夫曼编码

代码来自博主https://blog.csdn.net/sinat_28826891/article/details/79802739
自己添加了一些更详细注释。


#include "stdafx.h"
#define MAXSIZE 50
#include<string.h>
#include<stdio.h>
typedef struct
{
	char data;/*结点值*/
	int weight;/*权值*/
	int parent;/*父结点*/
	int left;/*左结点*/                 //这里定义成int,只记录结点的下标,不指向结点
	int right;/*右结点*/
	int flag;/*标志位*/
}huffnode;
typedef struct/*结点编码结构体*/
{
	char code[MAXSIZE];
	int start;
}huffcode;
huffnode htree[2 * MAXSIZE];
huffcode hcode[MAXSIZE];
int select(int i)/*找出权值最小的结点*/
{
	int k = 0x7fffffff;
	int j, q;
	for (j = 0; j <= i; j++)
		if (htree[j].weight<k&&htree[j].flag == -1)
		{
			k = htree[j].weight;
			q = j;
		}
	htree[q].flag = 1;/*将找到的结点标志位置1*/
	return q;
}
void creat_hufftree(int n)/*创建哈夫曼树*/
{
	int i, l, r;
	for (i = 0; i<2 * n - 1; i++)                                                               //n个结点生成赫夫曼树之后结点就变成2*n-1
		htree[i].parent = htree[i].left = htree[i].right = htree[i].flag = -1;/*均置-1*/
	for (i = n; i<2 * n - 1; i++)                                                  
	{
		l = select(i - 1);                          /*找出权值最小的两个结点的下标*/ 
		r = select(i - 1);                          //找第二个结点的时候flag已经变成了1,就会找到当前序列第二小的结点,并且把新合成的结点也加入进去参与计算了。
		htree[l].parent = i;                        //他们的parent是下标为i的结点
		htree[r].parent = i;
		htree[i].weight = htree[l].weight + htree[r].weight;/*左右结点权值相加等于新结点的权值*/
		htree[i].left = l;
		htree[i].right = r;
	}
}
void  creat_huffcode(int n)/*求哈夫曼编码*/
{
	int i, f, c;
	huffcode d;
	for (i = 0; i<n; i++)
	{
		d.start = n + 1;            //d.start 一开始都是等于7的,然后一个一个往前面填01
		c = i;
		f = htree[i].parent;      
		while (f != -1)                //根结点在creat的时候只是有了左右子树的值,没有父节点的值,父节点被初始化为-1了
		{
			if (htree[f].left == c)/*判断c是否是左子树*/
				d.code[--d.start] = '0';/*左边编码为0*/      //位置从下往上移动,所以应该--,反过来才是编码的顺序
			else
				d.code[--d.start] = '1';/*右边编码为1*/
			c = f;
			f = htree[f].parent;
		}
		hcode[i] = d;                               //d是一个结构体,里面包含一个code的数组,数组里存着编码,现在把这个结构体赋给hcode[i],i即代表第i个结点
	}
}
void display_huffcode(int n)/*输入各结点编码*/
{
	int i, k;
	printf("huffman is:\n");
	for (i = 0; i<n; i++)
	{
		printf("%c:", htree[i].data);/*输出结点*/
		for (k = hcode[i].start; k <= n; k++)
			printf("%c", hcode[i].code[k]);/*输出每个结点对应的编码*/                  //把code输出,start是从n开始往前填充的,start一直在--,已经减到了最开始的位置,正向输出就行
		printf("\n");
	}
}
void main()
{
	int n = 6;
	htree[0].data = 'a';
	htree[0].weight = 45;
	htree[1].data = 'b';
	htree[1].weight = 13;
	htree[2].data = 'c';
	htree[2].weight = 12;
	htree[3].data = 'd';
	htree[3].weight = 16;
	htree[4].data = 'e';
	htree[4].weight = 9;
	htree[5].data = 'f';
	htree[5].weight = 5;
	creat_hufftree(n);/*调用函数创建哈夫曼树*/
	creat_huffcode(n);/*调用函数构造哈夫曼编码*/
	display_huffcode(n);/*显示各结点哈夫曼编码*/
}

按照上面的数据搞了一张图出来
这里写图片描述

写赫夫曼树的时候也看了不同的人写的代码。这个代码相对来说非常简洁,有一点不同就是,他的parent,lchild,rchild并没有用指针连起来。只是在里面保存了下标。
开始那几个数据abcdef以及他们的weight是按照输入顺序没有动的。然后再连成一颗树的时候,通过保存下标的方法首先连接的是n+1到2n-1中最小的14,然后是25,30…最上面的100没有parent,有一个初始化了的-1。
还有就是把那个01的编码保存到数组的方式也很精妙,注释写了不赘述了。

以下是废话,不用看:
mlgb,最开始想要用最小堆实现最小优先级队列,在已有的叶节点上新建结点,insert,然后用最小优先级队列的extract-min实现连接,思路很简洁。but…写不出来啊,还搞了好久,最后向大佬的代码低头。结构体做成树还是数组的结构体那种,我真的写出来就报错,最重要的是,当你把功能模块化了之后,眼看着每块都能实现了。他连不起来啊。。。。这种去循环找到最小的两个值复杂度应该是o(n^2),最小堆的队列去找到o(nlgn)就行了。看了网上大家写的代码基本上没有用优先级队列去的。用了队列的是用的c++的algorithm的头文件里面一个sort queue。牛逼,看了一下C好像没有类似的功能。每次看别人的代码一来总是using namespace ,iostream等,用C++在写的人确实很多呢。也渐渐感到一些C++的优势,emm,伪工科的我只学过C语言呢,虽然两者很像,我基本也能看懂C++,但是我觉得还是有必要学习一下C++,特别是今天写赫夫曼的时候。马上就要上java的课了,不知道对这些有没有帮助。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值