哈夫曼编码的构建与输出

哈夫曼编码的构建与输出

halo各位看客们,最近接触到了一个很有趣且神奇的东西:哈夫曼编码!!!

那么什么是哈夫曼编码呢?我们以前看抗日神剧的时候可能经常接触到神秘电报密码这种东西,没错了,很多电报的破译就是由哈夫曼编码构成的,话不多说,让我们来见识一下这个神秘的东西。

先上我们在开头的宏定义以及头文件:

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

#define MaxLeaf 10000
#define MaxBit 100
#define MaxValue 10000
#define MaxNode MaxLeaf*2 - 1
typedef struct {
	double weight;
	int parent;
	int lchild;
	int rchild;
	char value;
}HuffNodeT;

typedef struct {
	int bit[MaxBit];
	int start;
}HuffNodeC;

HuffNodeT HuffNode[MaxNode];
HuffNodeC HuffCode[MaxLeaf];

在英文中有26个字母,在我们中文里也有五笔的25个一级简码,那么假如我们得到了一些字母以及他的使用频率,我们如何去得到它们的哈夫曼编码呢?首先我们需要得到一颗哈夫曼树:

void CreateHuffNode(HuffNodeT HuffNode[MaxNode],int n) {
	int i,j;
	int x1,x2;
	double m1,m2;
	for(i = 0;i < 2*n-1;i++) {
		HuffNode[i].lchild = -1;
		HuffNode[i].rchild = -1;
		HuffNode[i].parent = -1;
		HuffNode[i].weight = 0; 
	}
	for(i = 0; i < n;i++) {
		scanf(" %c %lf",&HuffNode[i].value,&HuffNode[i].weight);
		//printf("2");
	}
	 for(i = 0;i < n-1;i++) {
		m1 = m2 = MaxValue;
		x1 = x2 = 0;
		for (j = 0 ;j < n+i;j++) {
			if(HuffNode[j].weight < m1 && HuffNode[j].parent == -1) {
				m2 = m1;
				x2 = x1;
				m1 = HuffNode[j].weight;
				x1 = j;
			}
			else if (HuffNode[j].weight < m2 && HuffNode[j].parent == -1) {
				m2 = HuffNode[j].weight;
				x2 = j;
			}
		} 
		HuffNode[x1].parent = n+i;
		HuffNode[x2].parent = n+i;
		HuffNode[n+i].weight = m1 +m2;
		HuffNode[n+i].lchild = x1;
		HuffNode[n+i].rchild = x2; 
		//printf("2");
	 }
}

(注意!!在scanf时%c前要加空格 不然会导致输入错误)

我们使用结构体的方式使每一个除初始节点的节点有他的左右儿子以及父亲。

因为我们有N个节点,所以我们需要2*N - 1个节点空间来构建这颗树。

首先进行N - 2次循环,每次循环找到没有在树中的两个和最小的节点加入树,由此我们便得到了一颗哈夫曼树。

接下来就是编码哈夫曼树:

void CreateHuffCode(HuffNodeC HuffCode[MaxLeaf],int n) {
	HuffNodeC temp;
	int i,j;
	int c,p;
	for(i = 0;i < n;i++) {
		temp.start = n-1;
		c = i;
		p = HuffNode[c].parent;
		while(p != -1) {
			if(HuffNode[p].lchild == c) {
				temp.bit[temp.start] = 0;
			}
			else {
				temp.bit[temp.start] = 1;
			}
			temp.start--;
			c = p;
			p = HuffNode[c].parent;
		}
		for(j = temp.start;j < n;j++) {
			HuffCode[i].bit[j] = temp.bit[j];
			HuffCode[i].start = temp.start;
		}
	}
}

对这一课哈夫曼树,我们令每个分支上左儿子为0,右儿子为1,并将每一个节点的编码储存在编码数组中。

储存方式用到的逆向储存,通过start保存输出停止的位置。

最后是主程序,以及输出哈夫曼编码:

int main () {
	int i,j,n;
	scanf("%d",&n);
	CreateHuffNode(HuffNode,n);
	CreateHuffCode(HuffCode,n);
	for(i = 0; i < n;i++) {
		printf("%c:",HuffNode[i].value);
		for(j = HuffCode[i].start + 1;j < n;j++) {
			printf("%d",HuffCode[i].bit[j]);
		}
		printf("\n");
	}
	return 0;
} 

对此,我们输入数据测试结果:

可以看到,对于频率高的字符,得到的编码越简单,对于频率低的字符,得到的编码就越复杂。同时这也是比较符合我们的生活习惯的使用方式。

  • 8
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值