信息论 哈夫曼编码 C语言
哈夫曼编码是一种效率比较高的变长无失真信源编码方法。哈夫曼编码的编码方法,步骤如下:
- 将信源符号按概率从大到小的顺序排列,为方便起见,令p(a1)>=p(a2)>=…>=p(ai);
- 给两个概率最小的信源符号p(a(n-1))和p(an)各分配一个码位“0”和“1”,将这两个信源符号合并成一个新符号,并用这两个最小的概率之和作为新符号的概率,结果得到一个只包含(n-1)个信源符号的新信源,称为信源的第一次缩减信源S1;
- 将缩减信源S1的符号仍按概率从大到小的顺序排列,重复步骤2,得到只含(n-2)个符号的缩减信源S2;
- 重复上述步骤,直至缩减信源只剩下两个符号为止,此时所剩两个符号的概率之和必为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)