信息论与编码作业,要求用C语言对文本实现香农编码,要放寒假了,一并写到笔记里吧(新版编辑器居然不能对文章创建新分类了。。。。。。)
细节见注释
//我记得这段代码的注释写成于和初恋分手第二天
#include<cstdio>
#include <algorithm>
#include<iostream>
#include<cmath>
using namespace std;
struct node
{
char a;//字符
float b;//符号概率
int k;//码长
float p;//累加概率
int n[7];//字符的最终编码
};
node *count(FILE *a,node *d)//统计文本基本信息,各个符号的符号概率
{
char c;
int m=0;
c = getc(a);
for (; c != EOF;)//统计每个字符的个数和总字符个数
{
d[c - 32].b++;//利用ascii码,将字符直接转换成顺序表中的位置
c = getc(a);
m++;
}
printf("包含空格在内一共%d个字符。\n", m);
for (int i = 0; i < 95; i++)
{
d[i].b = d[i].b / m;//该字符的符号概率
if (d[i].b == 0) d[i].k = 0;//符号概率为零,码长也为零
else//求码长
{
//float b = 1 / d[i].b;
//float z = log2f(b);
float zyb = -log2f(d[i].b);
if (zyb - (int)zyb == 0) d[i].k = zyb;
else d[i].k = (int)(zyb + 1);
}
}
/*for (int i = 0; i < 95; i++)
{
printf("%c=", d[i].a);
printf("%d\n", d[i].k);
}*/
return d;
}
bool op(node j,node k)//按照符号概率排序
{
return j.b > k.b;
}
void leijia(node *j)//求累加概率
{
for (int i = 0; i < 95; i++)
{
if (j[i].b == 0) break;
if (i == 0) continue;
j[i].p = j[i - 1].p + j[i - 1].b;//累加概率=上一个的累加概率+上一个的符号概率
}
}
void binary(float j,int *n)//求累加概率小数部分的二进制码
{
//int n[7] = {0};
j = j - (int)j;
for (int i = 0; i < 7; i++)
{
j = j * 2;
n[i] = int(j);
j = j -(float)n[i];
}
}
void code(node *j)//最终编码,取二进制数的码长位
{
for (int i = 0; i < 95; i++)
{
int m[7] = { 0 };
binary(j[i].p, m);
for (int s = 0; s < j[i].k; s++)
{
j[i].n[s] = m[s];
}
//memcpy(j[i].n, m, j[i].k);
}
}
int main()
{
node d[95];
for (int i = 0; i < 95; i++)
{
d[i].a = i + 32;
d[i].b = 0;
d[i].k = 0;
d[i].p = 0;
}
FILE *a;
a = fopen("123.txt", "r");
count(a, d);
sort(d, d + 95, op);
leijia(d);
code(d);
printf("字符 符号概率 累加概率 字码长度 码字 \n");
for (int i = 0; i < 95; i++)
{
if (d[i].b == 0) continue;
printf("%c ", d[i].a);
printf("%f ", d[i].b);
printf("%f ", d[i].p);
printf("%d ", d[i].k);
for (int s = 0; s < d[i].k; s++)
{
printf("%d", d[i].n[s]);
}
printf("\n");
}
return 0;
}