题目:算术编码
具体代码:
#include<stdio.h>
#include<string.h>
#include<float.h>
#include<windows.h>
//code decode
double lowedge(int a,double *chance);
double highedge(int a,double *chance);
int main(){
SetConsoleOutputCP(65001);
printf("字符字典的个数为:");
char num[10],str[20];
int n,count,flag;
double chance[10],lenth;
double low=0.0,high=1.0;
int code2[20],m=0;
double sum=0,b=0.5;
scanf("%d",&n);
getchar();
//输入字典
printf("请输入字符和其对应的概率以及需要编码的字符串:\n");
for(int i=0;i<n;i++){
scanf("%c %Lf\n",&num[i],&chance[i]);
}
//输入要编码的字符串
gets(str);
count=strlen(str);//求字符个数
/*---------------------------------------
//检验是否输入成功
for(int i=0;i<n;i++){
printf("%c %f",num[i],chance[i]);
}
puts(str);
-------------------------------------------*/
//确定编码区间
for(int i=0;i<count;i++){
flag=0;
lenth=high-low;
for(int j=0;j<n;j++){
if(str[i]==num[j]){
flag=1;
high=low+lenth*highedge(j,chance);
low=low+lenth*lowedge(j,chance);
}
}
//判断是否含有非字典元素
if(flag==0){
printf("字符串含有非字典元素!\n编码结束!");
return 0;
}
}
printf("编码开始:\n");
//输出编码区间
printf("编码区间为:%.16Lf ~ %.16Lf\n",low,high);
//根据区间进行解码
while(1){
sum=sum+b;
if(sum<low){
code2[m]=1;
}
if(sum>high){
sum=sum-b;
code2[m]=0;
}
if((sum>low)&&(sum<high)){
code2[m]=1;
break;
}
b=(double)b/2;
m++;
}
//还原二进制代码并输出编码值和编码
printf("字符串编码为:");
for(int i=0;i<=m;i++){
printf("%d",code2[i]);
}
putchar('\n');
printf("字符串编码为:%.16Lf\n",sum);
printf("编码结束!\n");
//-----------------------------------------------
// start decoding
char c[20],d[20];
int L,N=0,countde=0;
double e=0.5,sumde=0.0,real,lowde=0.0,highde=1.0,lenthde=0.0;
printf("解码开始:\n输入要进行解码的二进制数组:");
gets(c);
L=strlen(c);
for(int i=0;i<L;i++){
real=c[i]-'0';
real=real*e;
sumde=sumde+real;
e=e/2;
}
printf("解码对应的十进制表示:%.16Lf\n",sumde);
printf("输入解码字符个数:");
scanf("%d",&N);
for(int i=0;i<N;i++){
lenthde=highde-lowde;
for(int j=0;j<n;j++){
if((sumde-lowde)/lenthde>lowedge(j,chance)&&(sumde-lowde)/lenthde<highedge(j,chance)){
d[i]=num[j];
highde=lowde+lenthde*highedge(j,chance);
lowde=lowde+lenthde*lowedge(j,chance);
}
}
}
printf("解码字符为:");
for(int i=0;i<N;i++){
printf("%c",d[i]);
}
putchar('\n');
printf("解码结束!");
return 0;
}
//构造求字符上下界的函数
double lowedge(int a,double *chance){
double lows=0;
for(int i=0;i<a;i++){
lows=lows+chance[i];
}
return lows;
}
double highedge(int a,double *chance){
double highs=0;
for(int i=0;i<=a;i++){
highs=highs+chance[i];
}
return highs;
}
运行结果如下:
补充说明:
1、如果使用UTF-8标准可以删去文中的头文件<windows.h>和SetConsoleOutputCP(65001);
2、C语言默认输出字符类型到小数点后6位,doublel类型有需要高精度输出的需要格式转换写成"%.16Lf"