_DataStructure_C_Impl:哈夫曼编码

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

#define infinity 10000		//定义一个无限大的值
//哈夫曼树类型定义
typedef struct{
	unsigned int weight;
	unsigned int parent,lchild,rchild;
}HTNode,*HuffmanTree;
typedef char **HuffmanCode;//存放哈夫曼编码
//返回树中n个结点中权值最小的结点序号
int Min(HuffmanTree t,int n){
	int i,flag;
	int f=infinity;		//f为一个无限大的值
	for(i=1;i<=n;i++)
		if(t[i].weight<f&&t[i].parent==0){
			f=t[i].weight;
			flag=i;
		}
	t[flag].parent=1;	//给选中的结点的双亲结点赋值1,避免再次查找该结点
	return flag;
}
//在n个结点中选择两个权值最小的结点序号,其中s1最小,s2次小
void Select(HuffmanTree *t,int n,int *s1,int *s2){
	int x;
	*s1=Min(*t,n);
	*s2=Min(*t,n);
	if((*t)[*s1].weight>(*t)[*s2].weight){		//如果序号s1的权值大于序号s2的权值,将两者交换,使s1最小,s2次小
		x=*s1;
		*s1=*s2;
		*s2=x;
	}
}
//构造哈夫曼树HT,哈夫曼树的编码存放在HC中,w为n个字符的权值
void HuffmanCoding(HuffmanTree *HT,HuffmanCode *HC,int *w,int n){ //叶子结点到根结点编码
	int m,i,s1,s2,start;
	unsigned int c,f;
	HuffmanTree p;
	char *cd;
	if(n<=1)
		return;
	m=2*n-1;
	*HT=(HuffmanTree)malloc((m+1)*sizeof(HTNode));	//第零个单元未用
	for(p=*HT+1,i=1;i<=n;++i,++p,++w){		//初始化n个叶子结点
		(*p).weight=*w;
		(*p).parent=0;
		(*p).lchild=0;
		(*p).rchild=0;
	}
	for(;i<=m;++i,++p){			//将n-1个非叶子结点的双亲结点初始化化为0
		(*p).parent=0;
	}
	for(i=n+1;i<=m;++i){		//构造哈夫曼树
		Select(HT,i-1,&s1,&s2);	//查找树中权值最小的两个结点
		(*HT)[s1].parent=(*HT)[s2].parent=i;
		(*HT)[i].lchild=s1;
		(*HT)[i].rchild=s2;
		(*HT)[i].weight=(*HT)[s1].weight+(*HT)[s2].weight;
	}
	//从叶子结点到根结点求每个字符的哈夫曼编码
	*HC=(HuffmanCode)malloc((n+1)*sizeof(char *));
	cd=(char *)malloc(n*sizeof(char));		//为哈夫曼编码动态分配空间
	cd[n-1]='\0';
	//求n个叶子结点的哈夫曼编码
	for(i=1;i<=n;i++){
		start=n-1;		//编码结束符位置
		for(c=i,f=(*HT)[i].parent;f!=0;c=f,f=(*HT)[f].parent)	//从叶子结点到根结点求编码
			if((*HT)[f].lchild==c)
				cd[--start]='0';
			else
				cd[--start]='1';
		(*HC)[i]=(char *)malloc((n-start)*sizeof(char));	//为第i个字符编码分配空间
		strcpy((*HC)[i],&cd[start]);	//将当前求出结点的哈夫曼编码复制到HC
	}
	free(cd);
}
//构造哈夫曼树HT,并从根结点到叶子结点求赫夫曼编码并保存在HC中
void HuffmanCoding2(HuffmanTree *HT,HuffmanCode *HC,int *w,int n){
	int s1,s2,i,m;
	unsigned int r,cdlen;
	char *cd;
	HuffmanTree p;

	if(n<=1)
		return;
	m=2*n-1;
	*HT=(HuffmanTree)malloc((m+1)*sizeof(HTNode));
	for(p=*HT+1,i=1;i<=n;i++,p++,w++)
	{
		(*p).weight=*w;
		(*p).parent=0;
		(*p).lchild=0;
		(*p).rchild=0;
	}
	for(;i<=m;++i,++p)
		(*p).parent=0;
	/*构造哈夫曼树HT*/
	for(i=n+1;i<=m;i++)
	{
		Select(HT,i-1,&s1,&s2);
		(*HT)[s1].parent=(*HT)[s2].parent=i;
		(*HT)[i].lchild=s1;
		(*HT)[i].rchild=s2;
		(*HT)[i].weight=(*HT)[s1].weight+(*HT)[s2].weight;
	}
	/*从根结点到叶子结点求赫夫曼编码并保存在HC中*/
	*HC=(HuffmanCode)malloc((n+1)*sizeof(char*));
	cd=(char*)malloc(n*sizeof(char));
	r=m;						/*从根结点开始*/
	cdlen=0;					/*编码长度初始化为0*/
	for(i=1;i<=m;i++)
		(*HT)[i].weight=0;		/*将weight域作为状态标志*/
	while(r)
	{
		if((*HT)[r].weight==0)/*如果weight域等于零,说明左孩子结点没有遍历*/
		{
			(*HT)[r].weight=1;	/*修改标志*/
			if((*HT)[r].lchild!=0)/*如果存在左孩子结点,则将编码置为0*/
			{
				r=(*HT)[r].lchild;
				cd[cdlen++]='0';
			}
			else if((*HT)[r].rchild==0)/*如果是叶子结点,则将当前求出的编码保存到HC中*/
			{
				(*HC)[r]=(char *)malloc((cdlen+1)*sizeof(char));
				cd[cdlen]='\0';
				strcpy((*HC)[r],cd);
			}
		}
		else if((*HT)[r].weight==1)/*如果已经访问过左孩子结点,则访问右孩子结点*/
		{
			(*HT)[r].weight=2;		/*修改标志*/
			if((*HT)[r].rchild!=0)
			{
				r=(*HT)[r].rchild;
				cd[cdlen++]='1';
			}
		}
		else						/*如果左孩子结点和右孩子结点都已经访问过,则退回到双亲结点*/
		{
			(*HT)[r].weight=0;
			r=(*HT)[r].parent;
			--cdlen;					/*编码长度减1*/
		}
	}
	free(cd);
}
void main(){
	HuffmanTree HT;
	HuffmanCode HC;
	int *w,n,i;
	printf("请输入叶子结点的个数: ");
	scanf("%d",&n);
	w=(int*)malloc(n*sizeof(int));		/*为n个结点的权值分配内存空间*/
	for(i=0;i<n;i++)
	{
		printf("请输入第%d个结点的权值:",i+1);
		scanf("%d",w+i);
	}
	HuffmanCoding(&HT,&HC,w,n);
	for(i=1;i<=n;i++)
	{
		printf("哈夫曼编码:");
		puts(HC[i]);
	}

	HuffmanCoding2(&HT,&HC,w,n);
	for(i=1;i<=n;i++)
	{
		printf("哈夫曼编码:");
		puts(HC[i]);
	}

	/*释放内存空间*/
	for(i=1;i<=n;i++)
		free(HC[i]);
	free(HC);
	free(HT);
	system("pause");
}

版权声明:本文为博主原创文章,未经博主允许不得转载|Copyright ©2011-2015,Supernatural, All Rights Reserved.

时间: 2024-10-29 19:05:44

_DataStructure_C_Impl:哈夫曼编码的相关文章

基于python的二元霍夫曼编码译码详细设计

一.设计题目 对一幅BMP格式的灰度图像(个人证件照片)进行二元霍夫曼编码和译码 二.算法设计 (1)二元霍夫曼编码: ①:图像灰度处理: 利用python的PIL自带的灰度图像转换函数,首先将彩色图片转为灰度的bmp图像,此时每个像素点可以用单个像素点来表示. ②:二元霍夫曼编码: 程序流程图: 详细设计: 统计像素点频率,首先通过python自带的PIL库的图像像素点读取函数read()获取灰度图像的所有像素点,通过循环遍历每个像素点,将每个出现的像素点值以及其次数以键值对的形式放入到pyt

霍夫曼编码求节省空间

霍夫曼编码将频繁出现的字符采用短编码,出现频率较低的字符采用长编码.具体的操作过程为:i)以每个字符的出现频率作为关键字构建最小优先级队列:ii)取出关键字最小的两个结点生成子树,根节点的关键字为孩子节点关键字之和,并将根节点插入到最小优先级队列中,直至得到一棵最优编码树. 霍夫曼编码方案是基于______策略的.用该方案对包含a到f6个字符的文件进行编码,文件包含100000个字符,每个字符的出现频率(用百分比表示)如表1-3所示,则与固定长度编码相比,该编码方案节省了______存储空间.

哈夫曼树与哈夫曼编码

哈夫曼树与哈夫曼编码 术语: i)路径和路径长度 在一棵树中,从一个结点往下可以达到的孩子或孙子结点之间的通路,称为路径. 路径中分支的数目称为路径长度.若规定根结点的层数为1,则从根结点到第L层结点的路径长度为L-1. ii)结点的权及带权路径长度 若对树中的每个结点赋给一个有着某种含义的数值,则这个数值称为该结点的权. 结点的带权路径长度为:从根结点到该结点之间的路径长度与该结点的权的乘积. iii)树的带权路径长度 树的带权路径长度:所有叶子结点的带权路径长度之和,记为WPL. 先了解一下

《数据结构复习笔记》--哈夫曼树,哈夫曼编码

先来了解一下哈夫曼树. 带权路径长度(WPL):设二叉树有n个叶子结点,每个叶子结点带有权值 wk,从根结点到每个叶子结点的长度为 lk,则每个叶子结点的带权路径长度之和就是: 最优二叉树或哈夫曼树: WPL最小的二叉树. [例]有五个叶子结点,它们的权值为{1,2,3,4,5},用此权值序列可以构造出形状不同的多个二叉树. 其中结果wpl最小值的是:33=(1+2)*3+(3)*2+(4+5)*2: 哈夫曼树的构造: 每次把权值最小的两棵二叉树合并, 代码: typedef struct Tr

C语言之霍夫曼编码学习

?1,霍夫曼编码描述哈夫曼树─即最优二叉树,带权路径长度最小的二叉树,经常应用于数据压缩. 在计算机信息处理中,"哈夫曼编码"是一种一致性编码法(又称"熵编码法"),用于数据的无损耗压缩.这一术语是指使用一张特殊的编码表将源字符(例如某文件中的一个符号)进行编码.这张编码表的特殊之处在于,它是根据每一个源字符出现的估算概率而建立起来的(出现概率高的字符使用较短的编码,反之出现概率低的则使用较长的编码,这便使编码之后的字符串的平均期望长度降低,从而达到无损压缩数据的目

数据结构课程设计-哈夫曼编码译码

//******************************************** //程序功能:哈夫曼编码及译码 // //日期:2014年11月18 // //******************************************** #include<stdio.h> #include<stdlib.h> #include<string.h> #include <windows.h> #define MAX 128 //叶子节点

哈夫曼编码(Huffman coding)的那些事,(编码技术介绍和程序实现)

前言 哈夫曼编码(Huffman coding)是一种可变长的前缀码.哈夫曼编码使用的算法是David A. Huffman还是在MIT的学生时提出的,并且在1952年发表了名为<A Method for the Construction of Minimum-Redundancy Codes>的文章.编码这种编码的过程叫做哈夫曼编码,它是一种普遍的熵编码技术,包括用于无损数据压缩领域.由于哈夫曼编码的运用广泛,本文将简要介绍: 哈夫曼编码的编码(不包含解码)原理 代码(java)实现过程 一

基于哈夫曼编码的文件压缩(c++版)

本博客由Rcchio原创 我了解到很多压缩文件的程序是基于哈夫曼编码来实现的,所以产生了自己用哈夫曼编码写一个压缩软件的想法,经过查阅资料和自己的思考,我用c++语言写出了该程序,并通过这篇文章来记录一下自己写该程序学到的东西.因为本人写的程序在压缩率上,还有提升的空间,所以本文将不定期更新,但程序整体的思路不会有较大的改动. 一.基于哈夫曼编码可实现压缩文件的原理分析 在计算机中,数据的存储都是二进制的,并且以字节作为基本的存储单位,像英文字母在文本中占一个字节,汉字占两个字节,我们把这种每一

哈夫曼编码和译码

构建哈夫曼原理:(每个元素都是叶子结点,N 个元素共有 2N-1 个结点) 有 N 个带权值的结点,将其按以下方法构建:①②③ ①选取 N 个结点集合中最小的两个权值结点构造成一个新的二叉树,且设置新结点的权值为左右孩子权值之和 ②将以上选取的两个最小权值结点从原集合中删除,向集合中加入 这两个结点的跟,即 1 中创建的新结点,此时集合 元素为 N = N - 2 + 1;  ③重复 ① ② 直到只剩下一个结点,该结点就是构建的二叉树的根 哈夫曼编码原理: 在哈夫曼树中,凡是左分支,即左孩子的全