哈夫曼编码最优前缀码的贪心算法

哈夫曼编码最优前缀码的贪心算法

哈夫曼编码是广泛地用于数据文件压缩的十分有效的编码方法。其压缩率通常在20%~90%之间。哈夫曼编码算法用字符在文件中出现的频率表来建立一个用0,1串表示各字符的最优表示方式。
前缀码:对每一个字符规定一个0,1串作为其代码,并要求任一字符的代码都不是其他字符代码的前缀。这种编码称为前缀码。编码的前缀性质可以使译码方法非常简单;例如001011101可以唯一的分解为0,0,101,1101
最优前缀码的二叉树总是一棵完全二叉树,即树中任意节点都有2个儿子,节点权重最小的节点在树的最深处。
根据上述分析,完成如下要求:
设计一个贪心算法,用程序设计语言实现,求解最优前缀编码问题。

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
typedef struct
{
	int weight;
	int parent,lchild,rchild;
}HFNode,*HFTree; 
typedef char *HFCode;//存储哈弗曼编码 
void select(HFTree *ht,int n,int *s1,int *s2)//选择两个parent为0,且weight最小的结点s1,s2 
{
	int i,min;
	for(i=1;i<=n;i++)
	{
		if((*ht)[i].parent==0)
		{
			min=i;
			break;
		} 
	}
	for(i=1;i<=n;i++)
	{
		if((*ht)[i].parent==0)
		{
			if((*ht)[i].weight<(*ht)[min].weight)
			{
				min=i;
			}
		}
	}
	*s1=min;
	for(i=1;i<=n;i++)
	{
		if((*ht)[i].parent==0 && i!=*s1)
		{
			min=i;
			break; 
		}
	}
	for(i=1;i<=n;i++)
	{
		if((*ht)[i].parent==0 && i!=*s1)
		{
			if((*ht)[i].weight<(*ht)[min].weight)
			{
				min=i;
			}
		}
	}
	*s2=min;
}
void CreatHFTree(HFTree *ht,int *w,int n)//w存放n个权值 
{
	int m,i,s1,s2;
	m=2*n-1;//总共的结点数 
	*ht=(HFTree)malloc ((m+1)*sizeof(HFNode)) ;
	for(i=1;i<=n;i++)   //对叶子结点初始化 
	{
		(*ht)[i].weight=w[i];
		(*ht)[i].lchild=0;
		(*ht)[i].rchild=0;
		(*ht)[i].parent=0;
	}
	for(i=n+1;i<=m;i++)//非叶子结点的初始化 
	{
		(*ht)[i].weight=0;
		(*ht)[i].lchild=0;
		(*ht)[i].rchild=0;
		(*ht)[i].parent=0;
	} 
	for(i=n+1;i<=m;i++)
	{
		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;
	}
}
void Code(HFTree *ht,HFCode *hc,int n)
{
	char *cd;
	int a[100];
	int i,start,j,p;
	float w;
	hc=(HFCode *)malloc ((n+1)*sizeof(char *));
	cd=(char *)malloc (n*sizeof(char));
	cd[n-1]='\0';
	for(i=1;i<=n;i++)
	{
		a[i]=0;
		start=n-1;//起始指针位置在最右边
		for(j=i,p=(*ht)[i].parent;p!=0;j=p,p=(*ht)[p].parent)//判断条件p!=0 
		{
			if((*ht)[p].lchild==j)
			{
				cd[--start]='0';
				a[i]++;
			}
			else
			{
				cd[--start]='1';
				a[i]++;
			}
		}
		hc[i]=(char *)malloc((n-start)*sizeof(char));
		strcpy(hc[i],&cd[start]);//将cd复制编码到hc 
	}
	free(cd);
	for(i=1;i<=n;i++) 
		printf("权值为%d的最优前缀编码为:%s\n",(*ht)[i].weight,hc[i]);
	for(i=1; i<=n; i++)
		w+=(*ht)[i].weight*a[i];
	w=w/100;
	printf("平均码长为: %.2f\n", w);
}
int main()
{
	HFTree ht;
	HFCode hc;
	int *w,i,n,q;
	printf("输入哈夫曼字符个数:\n");
	scanf("%d",&n);
	w=(int *)malloc((n+1)*sizeof(int));
	printf("\n输入%d个元素的权值:\n",n);
	for(i=1;i<=n;i++)
	{
		scanf("%d",&q);
		w[i]=q;
	}
	CreatHFTree(&ht,w,n);
	Code(&ht,&hc,n);
}

执行结果:
在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值