哈夫曼编码

实验内容 设需要编码的字符集为{d1, d2, …, dn},它们出现的频率为 {w1, w2, …, wn},应用 哈夫曼树构造最短的不等长编码方案。

输入一个字符串,每个字符出现的次数为,每个字符的权值。列如(helloworld,h :1 ,e :2

l :3,o:2,w:1,r:1, d:1)

第一个输入 的整数为填字符串的个数,第二个输入的整数为预测的带权路径之和,接下来输入字符串。如果预测大于实际输出为Yes,否则为NO。

列如

2

12

helloworld

66

sthinkyoucandoit

NO

Yes

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct
{
unsigned int weight; //用来存储各个结点的权值
unsigned int parent,LChild,RChild; //指向双亲、孩子结点的指针
} HTNode, *HuffmanTree; //动态分配数组,存储哈夫曼树
typedef char *HuffmanCode; //动态分配数组,存储哈夫曼树
int b[10]={1,1,1,1,1,1,1,1,1,1};
//存放权值
int ant(){  //用来求各个字符的权值
	int k=0;
	char a[100];
	scanf("%s",a);
	for(int i=0;i<strlen(a);i++){
		if(a[i]=='#')
		continue;
		k++;
		for(int j=i+1;j<strlen(a);j++){
			if(a[i]==a[j]){
				b[k]++;
				a[j]='#';
			}
		}
	}
	return k;
} 
///选择两个 parent 为 0,且 weight 最小的结点 s1 和 s2
void Select(HuffmanTree *ht,int n,int *s1,int *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;
}
} 
//构造哈夫曼树 ht,w 存放已知 n 个权值
void CrtHuffmanTree(HuffmanTree *ht,int *w,int n)
{
int m,i,s1,s2;
m=2*n-1; //总共的结点数
*ht=(HuffmanTree)malloc((m+1)*sizeof(HTNode));
for(i=1; i<=n; i++) //1-n 号存放叶子结点,初始化
{
(*ht)[i].weight=w[i];
(*ht)[i].LChild=0;
(*ht)[i].parent=0;
(*ht)[i].RChild=0;
}
for(i=n+1; i<=m; i++) //非叶子结点的初始化
{
(*ht)[i].weight=0;
(*ht)[i].LChild=0;
(*ht)[i].parent=0;
(*ht)[i].RChild=0;
}
//printf("\n?哈夫曼树为: \n");
for(i=n+1; i<=m; i++) //创建非叶子结点,建哈夫曼树
{ /*在(*ht)[1]~(*ht)[i-1]的范围内选择两个 parent 为 0 且 weight 最小的结点,其序号分别赋
值给 s1、s2*/
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;
//printf("%d (%d, %d)\n",(*ht)[i].weight,(*ht)[s1].weight,(*ht)[s2].weight);
}
//printf("\n");
}
//从叶子结点到根,逆向求每个叶子结点对应的哈夫曼编码
void CrtHuffmanCode(HuffmanTree *ht, HuffmanCode *hc, int n , int count )
{
char *cd; //定义的存放编码的空间
int a[100];
int i,start,p,w=0;
unsigned int c;
hc=(HuffmanCode *)malloc((n+1)*sizeof(char *)); //分配 n 个编码的头指针
cd=(char *)malloc(n*sizeof(char)); //分配求当前编码的工作空间
cd[n-1]='\0'; //从右向左逐位存放编码,首先存放编码结束符
for(i=1; i<=n; i++) //求 n 个叶子结点对应的哈夫曼编码
{
a[i]=0;
start=n-1; //起始指针位置在最右边
for(c=i,p=(*ht)[i].parent; p!=0; c=p,p=(*ht)[p].parent) //从叶子到根结点求编码
{
if( (*ht)[p].LChild==c)
{
cd[--start]='1'; //左分支标 1
a[i]++;
}
else
{
cd[--start]='0'; //右分支标 0
a[i]++;
}
}
hc[i]=(char *)malloc((n-start)*sizeof(char)); //为第 i 个编码分配空间
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];
if(count > w) {
	printf("Yes\n");
   }else{
   	printf("NO\n"); 
   }
}
int main()
{
HuffmanTree HT;
HuffmanCode HC;
int *w,i,n,wei,k;
int count1, j=0;
/*printf("**哈夫曼编码**\n" );
printf("请输入结点个数:" );
scanf("%d",&n);
w=(int *)malloc((n+1)*sizeof(int));
printf("\n 输入这%d 个元素的权值:\n",n);
for(i=1; i<=n; i++)
{
printf("%d: ",i);
fflush(stdin);
scanf("%d",&wei);
w[i]=wei;
}*/
scanf("%d",&i);
while(j<i){
	scanf("%d",&count1);
	k=ant();
    CrtHuffmanTree(&HT,b,k);
	CrtHuffmanCode(&HT,&HC,k,count1);
	j++;
}
system("pause");
return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值