Huffman编码与解码的实现

Huffman编码相信学过数据结构这么课的都知道,概念也比较好理解,但是一般好理解的算法,在实际实现的过程中总是会遇到各种问题,一方面个人认为是对算法的实现过程不熟,另一方面在实际实现的过程中可以提升自己实现算法的能力,将自己的想法实现后还是比较满足的。下面是本人亲自实现的Huffman编码与解码的C语言实现,主要是记录一下自己当时的想法,供以后备忘吧。

数据结构定义如下:

typedef struct{
	unsigned int weight;
	unsigned int parent,lchild,rchild;
}HTNode, * HuffmanTree;

typedef char * * HuffmanCode;

建Huffman树的过程是使用顺序结构数组存储树,由于没有度为一的节点,因此总数为2*n - 1个节点,n为叶子节点个数,也是待编码的字符个数。

建树的关键代码如下:

        //建立Huffman树,初始化1到n号元素的parent都为0,每次从parent为0的元素中
	//挑选最小的两个建树之后,将它们的parent都置为对应号码
	for(i = n + 1; i <= m; i++)
	{
		int  min1, min2;
		int j;
		for(j = 1; j <= i - 1; j++)
			if(HT[j].parent == 0) {min1 = j; break;}
		for(j = 1; j <= i - 1; j++)
		{
			if(HT[j].parent != 0) continue;
			if(HT[j].weight < HT[min1].weight)
				min1 = j;
		}
		HT[min1].parent = i;

		for(j = 1; j <= i - 1; j++)
			if(HT[j].parent == 0) {min2 = j; break;}
		for(j = 1; j <= i - 1; j++)
		{
			if(HT[j].parent != 0) continue;
			if(HT[j].weight < HT[min2].weight)
				min2 = j;
		}
		HT[min2].parent = i;

		HT[i].lchild = min1;
		HT[i].rchild = min2;
		HT[i].weight = HT[min1].weight + HT[min2].weight;
	}

编码过程是更加树的结构,对每个非叶子节点的左子树为‘0’,右子树为‘1’。实现如下:

//编码
	HuffmanCode HC = (HuffmanCode)malloc(n*sizeof(char *));
	char * cd = (char *)malloc(n*sizeof(char));
	cd[n-1] = ‘\0‘;
	for(i = 0; i < n; i++)
	{
		int end = n - 1;
		int cur = i + 1;
		for (int a = HT[cur].parent; a != 0; cur = a, a = HT[a].parent)
		{
			if (HT[a].lchild == cur) cd[--end] = ‘0‘;
			else if (HT[a].rchild == cur) cd[--end] = ‘1‘;
		}
		HC[i] = (char*)malloc((n-end)*sizeof(char));
		strcpy(HC[i], &cd[end]);
	}
	free(cd);

全部实现,封装在一个HuffmanEncode函数中。

HuffmanCode HuffmanEncode(HuffmanTree & HT, unsigned int * w, int n)
{
	int m = 2 * n - 1;
	HT = (HuffmanTree)malloc((m+1)*sizeof(HTNode)); //第一个不用
	int i;
	for(i = 1; i <= n; i++)
	{
		HT[i].weight = w[i-1];
		HT[i].parent = 0;
		HT[i].lchild = 0;
		HT[i].rchild = 0;
	}
	for(i = n + 1;i <= m; i++)
	{
		HT[i].weight = 0;
		HT[i].parent = 0;
		HT[i].lchild = 0;
		HT[i].rchild = 0;
	}
	//建立Huffman树,初始化1到n号元素的parent都为0,每次从parent为0的元素中
	//挑选最小的两个建树之后,将它们的parent都置为对应号码
	for(i = n + 1; i <= m; i++)
	{
		int  min1, min2;
		int j;
		for(j = 1; j <= i - 1; j++)
			if(HT[j].parent == 0) {min1 = j; break;}
		for(j = 1; j <= i - 1; j++)
		{
			if(HT[j].parent != 0) continue;
			if(HT[j].weight < HT[min1].weight)
				min1 = j;
		}
		HT[min1].parent = i;

		for(j = 1; j <= i - 1; j++)
			if(HT[j].parent == 0) {min2 = j; break;}
		for(j = 1; j <= i - 1; j++)
		{
			if(HT[j].parent != 0) continue;
			if(HT[j].weight < HT[min2].weight)
				min2 = j;
		}
		HT[min2].parent = i;

		HT[i].lchild = min1;
		HT[i].rchild = min2;
		HT[i].weight = HT[min1].weight + HT[min2].weight;
	}

	//编码
	HuffmanCode HC = (HuffmanCode)malloc(n*sizeof(char *));
	char * cd = (char *)malloc(n*sizeof(char));
	cd[n-1] = ‘\0‘;
	for(i = 0; i < n; i++)
	{
		int end = n - 1;
		int cur = i + 1;
		for (int a = HT[cur].parent; a != 0; cur = a, a = HT[a].parent)
		{
			if (HT[a].lchild == cur) cd[--end] = ‘0‘;
			else if (HT[a].rchild == cur) cd[--end] = ‘1‘;
		}
		HC[i] = (char*)malloc((n-end)*sizeof(char));
		strcpy(HC[i], &cd[end]);
	}
	free(cd);
	return HC;
}

对于编码后得到的编码字符序列HC,结果过程只需找到对应的下标即可。如下:

int HuffmanDecode(HuffmanTree HT,char* code, int n)
{
	int i = 0, r;
	for(int j = 1; j <= 2*n-1; j++)
		if(HT[j].parent == 0) {r = j;break;}

	while(code[i] == ‘0‘ || code[i] == ‘1‘)
	{
		if(code[i] == ‘0‘)
			r = HT[r].lchild;
		else if(code[i] == ‘1‘)
			r = HT[r].rchild;
		i++;
	}
	return r;
}

最后,主函数中的调用如下,整个实现起来后比较方便。

int main()
{
	printf("请输入待编码的字符个数:\n");
	int n = 0;
	scanf("%d", &n);
	char codechar[n];
	unsigned int weight[n];

	printf("请输入编码字符:\n");
	scanf("%s", codechar);
	for(int i = 0; i < n; i++)
	{
		printf("\n请输入第%d个字符对应的权重:\n", i+1);
		scanf("%d", &weight[i]);
	}

	HuffmanTree ht;
	HuffmanCode hc = HuffmanEncode(ht, weight, n);
	printf("\n构建的赫夫曼树如下(权重-左孩子-右孩子-父亲):\n");
	for(int i = 1; i <= 2*n-1; i++)
	{
		printf("%d\t%d\t%d\t%d\n", ht[i].weight, ht[i].lchild, ht[i].rchild, ht[i].parent);
	}
	printf("\n每个字符对应的编码如下:\n");
	for(int i = 0; i < n; i++)
	{
		printf("%c\t:\t%s\n", codechar[i], hc[i]);
	}

	printf("\n请输入待解码的编码字符串:");
	char str[n];
	scanf("%s", str);
	int hcindex = HuffmanDecode(ht, str, n);
	printf("%s编码的字符是:%c\n", str, codechar[hcindex-1]);
	return 0;
}

结果如下:

时间: 2024-07-31 14:07:40

Huffman编码与解码的实现的相关文章

Huffman编码和解码

一.Huffman树 定义: 给定n个权值作为n个叶子结点,构造一棵二叉树,若该树的带权路径达到最小,这样的二叉树称为最优二叉树,也称为霍夫曼树(Huffman树). 特点:     Huffman树是带权路径长度最短的树,权值较大的节点离根节点较近 权值 = 当前节点的值 * 层数,wpl最小的值,就是Huffman树 创建步骤  举例  {13,7,8,3,29,6,1} 1.从小到大进行排序,将每一个数据视为一个节点,每一个节点都可视为一个二叉树 2.取出根节点权值两个最小的二叉树 3.组

Huffman 编码压缩算法

前两天发布那个rsync算法后,想看看数据压缩的算法,知道一个经典的压缩算法Huffman算法.相信大家应该听说过 David Huffman 和他的压缩算法—— Huffman Code,一种通过字符出现频率,Priority Queue,和二叉树来进行的一种压缩算法,这种二叉树又叫Huffman二叉树 —— 一种带权重的树.从学校毕业很长时间的我忘了这个算法,但是网上查了一下,中文社区内好像没有把这个算法说得很清楚的文章,尤其是树的构造,而正好看到一篇国外的文章<A Simple Examp

Huffman对文件编码和解码

考核实验中的一个,我也认为较为难的一个,其实也不是很难,只是有点复杂,只要分解成多个问题去解决就好了 比如你要知道Huffman是怎样对文件进行编码和解码的 然后需要知道怎么去建Huffman二叉树,建好了Huffman树 然后就是对其进行编码  最后是解码 只要把每个过程弄清楚了,用几天时间(对本科生而言)写出来应该还是有可能的 下面的代码是某位同学写的,经过其本人允许我决定贴到我的博客中供大家学习,但是如果按照源代码来演示的话,你懂得-- 期中要编码的txt文件必须放在.cpp源文件同个文件

Jcompress: 一款基于huffman编码和最小堆的压缩、解压缩小程序

前言 最近基于huffman编码和最小堆排序算法实现了一个压缩.解压缩的小程序.其源代码已经上传到github上面: Jcompress下载地址 .在本人的github上面有一个叫Utility的repository,该分类下面有一个名为Jcompress的目录便是本文所述的压缩.解压缩小程序的源代码.后续会在Utility下面增加其他一些实用的小程序,比如基于socket的文件断点下载小程序等等.如果你读了此文觉得还不错,不防给笔者的github点个star, 哈哈.在正式介绍Jcompres

Huffman编码之文件的解/压缩

问题描述:           生活中文件压缩技术可谓随处可见,在数据的密集型传输中文件压缩是一项重要的实用性技术.例如:较大文件的下载,传输等.常见的文件压缩工具有winRAR,2345好压,快压(KuaiZip)等,这些工具已经开发的相当牛逼,但是作为入门级的程序员来说,不能只停留在观摩的立场上,扮演使用者的角色.有必要深入了解其底层的基础实现方式,掌握基础的文件压缩原理,所以在此将其视为一个小型项目列出,以供大家交流探讨,相互学习.... ★在此之前,先来说说什么是文件压缩,用以抛出一个基

Huffman编码实现压缩解压缩

这是我们的课程中布置的作业,找一些资料将作业完成,顺便将其写到博客,以后看起来也方便. 原理介绍 什么是Huffman压缩 Huffman( 哈夫曼 ) 算法在上世纪五十年代初提出来了,它是一种无损压缩方法,在压缩过程中不会丢失信息熵,而且可以证明 Huffman 算法在无损压缩算法中是最优的. Huffman 原理简单,实现起来也不困难,在现在的主流压缩软件得到了广泛的应用.对应用程序.重要资料等绝对不允许信息丢失的压缩场合, Huffman 算法是非常好的选择. 怎么实现Huffman压缩

【POJ1521】【HDU1053】Entropy 哈夫曼(Huffman)编码

#include <stdio.h> int main() { puts("转载请注明出处谢谢"); puts("http://blog.csdn.net/vmurder/article/details/43020921"); } 题意: 输出字符串的长度*8.huffman编码长度.两者比值. 题解: huffman编码: 我们发现对于一个字符串,如果我们把它变成01串,比如ABCDE 那么我们需要 A : 000 B : 001 C : 010 D

[老文章搬家] 关于 Huffman 编码

按:去年接手一个项目,涉及到一个一个叫做Mxpeg的非主流视频编码格式,编解码器是厂商以源代码形式提供的,但是可能代码写的不算健壮,以至于我们tcp直连设备很正常,但是经过一个UDP数据分发服务器之后,在偶尔有丢包的情况下解码器会偶发崩溃,翻了翻他们的代码觉得可能问题出在Huffman这一块.水平有限也没有看太懂他们的源码,而且我也不是科班出身当时对Huffman编码算法只是知道这么个名字,还好服务端软件那边做了修改,解决了丢包的问题.在回家过年的火车上想起这件事,阅读了一些关于Huffman编

20172303 2018-2019-1《程序设计与数据结构》哈夫曼树编码与解码

20172303 2018-2019-1<程序设计与数据结构>哈夫曼树编码与解码 哈夫曼树简介 定义:给定n个权值作为n个叶子结点,构造一棵二叉树,若带权路径长度达到最小,称这样的二叉树为最优二叉树,也称为哈夫曼树(Huffman Tree).哈夫曼树是带权路径长度最短的树,权值较大的结点离根较近. 带权路径长度(Weighted Path Length of Tree,简记为WPL) 结点的权:在一些应用中,赋予树中结点的一个有某种意义的实数. 结点的带权路径长度:结点到树根之间的路径长度与