信息论 输入概率的哈夫曼编码 C语言

信息论 哈夫曼编码 C语言

哈夫曼编码是一种效率比较高的变长无失真信源编码方法。哈夫曼编码的编码方法,步骤如下:

  1. 将信源符号按概率从大到小的顺序排列,为方便起见,令p(a1)>=p(a2)>=…>=p(ai);
  2. 给两个概率最小的信源符号p(a(n-1))和p(an)各分配一个码位“0”和“1”,将这两个信源符号合并成一个新符号,并用这两个最小的概率之和作为新符号的概率,结果得到一个只包含(n-1)个信源符号的新信源,称为信源的第一次缩减信源S1;
  3. 将缩减信源S1的符号仍按概率从大到小的顺序排列,重复步骤2,得到只含(n-2)个符号的缩减信源S2;
  4. 重复上述步骤,直至缩减信源只剩下两个符号为止,此时所剩两个符号的概率之和必为1.然后从最后一级缩减信源开始,依编码路径向前返回,就得到各信源符号所对应的码字;

实验要求

1、信源符号个数随机,信源符号及信源概率手动输入;
2、Huffman编码中的排序不可直接调用函数,需实现概率叠加后排序时出现相等情况下的两种不同编码;
3、输出每个信源符号的编码结果,输出形式不限;
4、交互界面的友好性。

程序源代码

#include<stdio.h>
#include<math.h>
#define G 200
void code(int M);
void CODE(int M);
struct abc
{
	int b;
	int d[G];
	float num;
}D[G],E;
float a[G] = {0},t = 0,m[G] = {0},k = 0,H = 0;
int K[G] = {0},i,j,N,s[G][G] = {0},x;
void main()
{
	printf ( "\n" );
	printf ( "\n" );
	printf ( "                  	******************哈夫曼编码******************\n" );
	printf ( "	 _____________________________________________________________________________\n" );
	printf ( "	|---->                       请选择输入你要操作的选择                    <----|\n" );
	printf ( "	|---->                                                                   <----|\n" );
	printf ( "	|---->                            ***      ***                           <----|\n" );
	printf ( "	|---->   如果输入0             *******    *******        如果输入1       <----|\n" );
	printf ( "	|---->                       **********************                      <----|\n" );
	printf ( "	|---->                       **********************                      <----|\n" );
	printf ( "	|---->   后来者居下            ******************        后来者居上      <----|\n" );
	printf ( "	|---->                           **************                          <----|\n" );
	printf ( "	|---->                             **********                            <----|\n" );
	printf ( "	|---->                               ******                              <----|\n" );
	printf ( "	|---->                                 **                                <----|\n" );
	printf ( "	|---->                                                                   <----|\n" );
	printf ( "	|___________________________________________________________________________  |\n" );
	printf("           请输入0或1赋给x(如果输入0,后来者居下;如果输入1,后来者居上):");
	scanf("%d",&x);
	if(x==0)
	{
		printf("           请输入信源符号个数N:");
		scanf("%d",&N);
		for(i = 0;i<N;i++)
		{
			printf("\t   第%d个信源概率:",i+1);
			scanf("%f",&a[i]);
			t+=a[i];
		}
		for(i = 0;i<N;i++)
		{
			if(a[i]<0)
				printf("输入错误!");
		}
		if(t!=1)
		{
			printf("     输入数据不符合要求,请重新输入\n:");
			t = 0;
		}
		else
		{
			for(i=0;i<N-1;i++)
			{
				for(j=i+1;j<N;j++)
				{
					if(a[i]<a[j])
					{
						t = a[i];   //选择排序
						a[i] = a[j];
						a[j] = t;
					}
				}
			}
			/*for(i=N;i>=1;i--)
			{
				for(j=0;j<N-1;j++)
				{
					if(a[j]<a[j+1])
					{
						t = a[j];				//冒泡排序
						a[j] = a[j+1];
						a[j+1] = t;
					}
				}
			}*/
		for(i=0;i<N;i++)
			{
				D[i].b = 1;
				D[i].d[0] = i;
				D[i].num = a[i];
			}
			for(i = 0;i<N;i++)
			{
				m[i] =- log10(a[i])/log10(2.0);//m[i]为自信息量 
			}
			code(N);
			for(i=0;i<N;i++)
			{
				H += a[i] * m[i];//H为信源熵
				k += a[i] * K[i];//k为平均码长
			}
			printf("         -----------------------------------------------------------------------\n");
			printf("         信源符号ai\t\t概率p(ai)\t\t码长Ki\t\t码字\n");
			printf("         -----------------------------------------------------------------------\n");
			for(i=0;i<N;i++)
			{
				printf("            a%d\t\t\t   %-4.2f\t\t\t%d\t\t",i+1,a[i],K[i]);
				for(j=K[i];j>0;j--)
				{
					printf("%d",s[i][j-1]);
				}
					printf("\n");
			}
			printf("         -----------------------------------------------------------------------\n");
			printf("         信源熵H=%5.3f(bit/sign)     平均码长k=%5.3f(bit/sign)   编码效率n=%4.1f%%\n",H,k,100*(H/k));
			printf("         -----------------------------------------------------------------------\n");
		}
	}
	else 
		if(x!=0 && x!=1)
			{
				printf("            看你长得帅给你第二次机会,乖乖的回去输入0或1\n");
		}
		else
		{
			printf("           请输入信源符号个数N:");
			scanf("%d",&N);
			for(i = 0;i<N;i++)
			{ 
				printf("           第%d个信源概率:",i+1);
				scanf("%f",&a[i]);
				t+=a[i];
			}
			for(i = 0;i<N;i++)
			{
				if(a[i]<0)
					printf("输入错误!");
			}
			if(t!=1)
			{
				printf("         输入数据不符合要求,请重新输入\n:");
				t = 0;
			}
			else
			{
				for(i=0;i<N-1;i++)
				{
					for(j=i+1;j<N;j++)
					{
						if(a[i]<a[j])
						{
							t = a[i];   //选择排序
							a[i] = a[j];
							a[j] = t;
						}
					}
				}
				for(i = 0;i<N;i++)
				{
					D[i].b = 1;
					D[i].d[0] = i;
					D[i].num = a[i];
				}
				for(i = 0;i<N;i++)
				{
					m[i] =- log10(a[i])/log10(2.0);//m[i]为自信息量 
				}
				CODE(N);
				for(i=0;i<N;i++)
				{
					H += a[i] * m[i];//H为信源熵
					k += a[i] * K[i];//k为平均码长
				}
				printf("         -----------------------------------------------------------------------\n");
				printf("         信源符号ai\t\t概率p(ai)\t\t码长Ki\t\t码字\n");
				printf("         -----------------------------------------------------------------------\n");
				for(i=0;i<N;i++)
				{
					printf("            a%d\t\t\t   %-4.2f\t\t\t%d\t\t",i+1,a[i],K[i]);
					for(j=K[i];j>0;j--)
					printf("%d",s[i][j-1]);
					printf("\n");
				}
				printf("         -----------------------------------------------------------------------\n");
				printf("         信源熵H=%5.3f(bit/sign)     平均码长k=%5.3f(bit/sign)    编码效率n=%4.1f%%\n",H,k,100*(H/k));
				printf("         -----------------------------------------------------------------------\n");
			}
		}
		getchar();
		getchar();
}

void code(int M)
{
	for(i=0;i<M-1;i++)
	{
		for(j=i+1;j<M;j++)
		{
			if(D[i].num < D[j].num )
			{
				E = D[i];
				D[i] = D[j];//选择排序
				D[j] = E;
			}
		}
	}
	for(i=0;i<D[M-2].b;i++)
	{
		j = D[M-2].d[i];
		s[j][K[j]] = 0;
		K[j] += 1;
	}
	for(i=0;i<D[M-1].b;i++)
	{
		j = D[M-1].d[i];
		s[j][K[j]] = 1;//码元
		K[j] += 1;//对应码长
	}
	D[M-2].num += D[M-1].num;//两个最小概率相加	
	for(i=0;i<D[M-1].b;i++)
	{
		D[M-2].d[i+D[M-2].b] = D[M-1].d[i];
	}
	D[M-2].b += D[M-1].b;
	M--;
	if(M>1)
	{
		code(M);
	}	
}
void CODE(int M)
{
	for(i=0;i<M-1;i++)
	{
		for(j=i+1;j<M;j++)
		{
			if(D[i].num <= D[j].num )
		{
			E = D[i];
			D[i] = D[j];//冒泡排序
			D[j] = E;
		}
		}
	}
	for(i=0;i<D[M-2].b;i++)
	{
		j = D[M-2].d[i];
		s[j][K[j]] = 0;
		K[j] += 1;
	}
	for(i=0;i<D[M-1].b;i++)
	{
		j = D[M-1].d[i];
		s[j][K[j]] = 1;
		K[j] += 1;
	}
	D[M-2].num += D[M-1].num;//排序后,最后两个最小概率相加	
	for(i=0;i<D[M-1].b;i++)
	{
		D[M-2].d[i+D[M-2].b] = D[M-1].d[i];
	}
	D[M-2].b += D[M-1].b;
	M--;//降级
	if(M>1)//继续执行
	{
		CODE(M);
	}	
}
叠加后概率与之前相等排序,排于与之相等的概率之后.
函数模块:
void code(int M)
{
	for(i=0;i<M-1;i++)
	{
		for(j=i+1;j<M;j++)
		{
			if(D[i].num < D[j].num )
			{
				E = D[i];
				D[i] = D[j];//选择排序
				D[j] = E;
			}
		}
	}
	for(i=0;i<D[M-2].b;i++)
	{
		j = D[M-2].d[i];
		s[j][K[j]] = 0;
		K[j] += 1;
	}
	for(i=0;i<D[M-1].b;i++)
	{
		j = D[M-1].d[i];
		s[j][K[j]] = 1;//码元
		K[j] += 1;//对应码长
	}
	D[M-2].num += D[M-1].num;//两个最小概率相加	
	for(i=0;i<D[M-1].b;i++)
	{
		D[M-2].d[i+D[M-2].b] = D[M-1].d[i];
	}
	D[M-2].b += D[M-1].b;
	M--;
	if(M>1)
	{
		code(M);
	}	
}
叠加后概率与之前相等排序,排于与之相等的概率之前
函数模块:
void CODE(int M)
{
	for(i=0;i<M-1;i++)
	{
		for(j=i+1;j<M;j++)
		{
			if(D[i].num <= D[j].num )
		{
			E = D[i];
			D[i] = D[j];//冒泡排序
			D[j] = E;
		}
		}
	}
	for(i=0;i<D[M-2].b;i++)
	{
		j = D[M-2].d[i];
		s[j][K[j]] = 0;
		K[j] += 1;
	}
	for(i=0;i<D[M-1].b;i++)
	{
		j = D[M-1].d[i];
		s[j][K[j]] = 1;
		K[j] += 1;
	}
	D[M-2].num += D[M-1].num;//排序后,最后两个最小概率相加	
	for(i=0;i<D[M-1].b;i++)
	{
		D[M-2].d[i+D[M-2].b] = D[M-1].d[i];
	}
	D[M-2].b += D[M-1].b;
	M--;//降级
	if(M>1)//继续执行
	{
		CODE(M);
	}	
}

输出结果

一、第一种编码方式
输入 :0
个数 :5
概率:0.4 0.2 0.2 0.1 0.1
输出结果如下图:
在这里插入图片描述
二、第二种编码方式
输入 :0
个数 :5
概率:0.4 0.2 0.2 0.1 0.1
输出结果如下图:
在这里插入图片描述

代码提供给有需要的人!!!
参考链接:(https://blog.csdn.net/qq_32786873/article/details/49863127)

  • 11
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值