信息論與編碼作業,要求用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;
}