算数编码

本文介绍了一种基于算术编码的压缩算法实现过程。该算法通过定义概率模型,为不同元素分配相应的概率,并据此对输入序列进行编码,最终生成压缩后的编码字符串。文章详细描述了初始化概率模型、设置系列数据及进行算术编码的具体步骤。
摘要由CSDN通过智能技术生成

#include <stdio.h>
#include <string.h> /*for strcpy()*/
#include <math.h> /*for log(),pow()*/
#include <malloc.h> /*for malloc(),free()*/
#include <stdlib.h> /*for abs()*/

#define CACHE_SIZE 128

typedef char element_type;
typedef double element_chance;

typedef struct element_set /*用来描述一个概率模型*/
{
    int num;
    element_type *name;
    element_chance  *chance;
}element_set;

int init_elements(element_set *);
int set_elements(element_set *); /*设置一个概率模型的值*/
int set_series(char **); /*设置一个待压缩序列*/
int coder(element_set *,char *,char **); /*对待压缩序列用给定概率模型进行算术编码*/
int set_element_name(char *);
int set_element_chance(double *);
int check_elements(element_set *);
int print_elements_info(element_set *);

int main(void)
{
    element_set set;
    element_type *series=0;
    char *code=0;
    if(init_elements(&set))
    {
        printf("init_elements error!/n");
        return 1;
    }
    if(set_elements(&set))
    {
        printf("set_elements error!/n");
        return 1;
    }
    if(set_series(&series))
    {
        printf("set_series error!/n");
        return 1;
    }
    if(coder(&set,series,&code))
    {
        printf("coder error!/n");
        return 1;
    }
    printf("the code is:%s/n",code);
    system("pause");
    return 0;
}

int init_elements(element_set *set)
{
    if(!set)
    {
        printf("pointer is NULL!/n");
        return 1;
    }
    set->num=0;
    set->name=0;
    set->chance=0;
    return 0;
}

int set_elements(element_set *set)
{
    int i,j,flag=0;
    do
    {
        printf("how many elements in the set?/n");
        do
        {
            scanf("%d",&(set->num));
            while(getchar()!='/n')
            {
                ;
            }
            if(set->num<1)
            {
                flag=1;
                printf("the num should greater than 0!/n");
            }
            else
            {
                flag=0;
            }
        }while(set->num<1);
        set->name=malloc(set->num*sizeof(element_type));
        set->chance=malloc(set->num*sizeof(element_chance));
        if(!(set->name&&set->chance))
        {
            printf("malloc error!/n");
            return 1;
        }
        printf("please input the elements name and their chances./n");
        for(i=0;i<set->num;i++)
        {
            do
            {
                printf("%d:/n",i+1);
                printf("/tname:/n/t/t");
                if(set_element_name(&(set->name[i])))
                {
                    printf("set_element_name error!/n");
                    return 1;
                }
                flag=0;
                for(j=0;j<i;j++)
                {
                    if(set->name[i]==set->name[j])
                    {
                        flag=1;
                        printf("the name is same with /"%d/"!/n",j+1);
                        printf("please reinput./n");
                        break;
                    }
                }
            }while(flag);
            do
            {
                printf("/tchance:/n/t/t");
                if(set_element_chance(&(set->chance[i])))
                {
                    printf("set_element_chance error!/n");
                    return 1;
                }
                if(set->chance[i]<0||set->chance[i]>1)
                {
                    flag=1;
                    printf("chance error!/n");
                    printf("please reinput./n");
                }
                else
                {
                    flag=0;
                }
            }while(flag);
        }
        do
        {
            if(check_elements(set))
            {
                flag=1;
                printf("total chance is not 1!/n");
                printf("the elements information is:/n");
                if(print_elements_info(set))
                {
                    printf("print_elements_info error!/n");
                    return 1;
                }
                printf("which element's chance do you want to modify?(0 to reinput all and negatives to quit.)/n");
                scanf("%d",&i);
                while(getchar()!='/n')
                {
                    ;
                }
                if(i)
                {
                    if(i>0)
                    {
                        printf("%d:/n",i+1);
                        printf("/tchance:/n/t/t");
                        if(set_element_chance(&(set->chance[i])))
                        {
                            printf("set_element_chance error!/n");
                            return 1;
                        }
                    }
                    else
                    {
                        return 1;
                    }
                }
                else
                {
                    break;
                }
            }
            else
            {
                flag=0;
            }
        }while(flag);
    }while(flag);
    return 0;
}

int set_series(char **series)
{
    char *buf,tmp;
    int i,j=0;
    if(*series)
    {
        printf("pointer may be using by other procedure!/n");
        return 1;
    }
    printf("please input the series./n");
    while(++j>0)
    {
        buf=malloc((j*CACHE_SIZE+1)*sizeof(char));
        if(!buf)
        {
            printf("malloc error!(may the series is too long.)/n");
            return 1;
        }
        if(*series)
        {
            strcpy(buf,*series);
            free(*series);
        }
        *series=buf;
        for(i=0;i<CACHE_SIZE;i++)
        {
            tmp=getchar();
            if(tmp=='/n')
            {
                break;
            }
            buf[(j-1)*CACHE_SIZE+i]=tmp;
        }
        buf[(j-1)*CACHE_SIZE+i]='/0';
        if(tmp=='/n')
        {
            break;
        }
    }
    return 0;
}

int coder(element_set *set,char *series,char **code)
{
    int i,j,k;
    double low,width,chance;
    double fractional;
    if(!(set&&series)||*code)
    {
        printf("wrong pointer!/n");
        return 1;
    }
    for(i=low=0,width=1;series[i]!='/0';i++)
    {
        for(j=0;j<set->num;j++)
        {
            if(series[i]==set->name[j])
            {
                break;
            }
        }
        if(series[i]!=set->name[j]) /*set->num<0 and other errors*/
        {
            printf("error!(either series not in element_set or an ill element_set.)/n");
            return 1;
        }
        for(k=0,chance=0;k<j;k++)
        {
            chance+=set->chance[k];
        }
        low+=width*chance;
        width*=set->chance[j];
    }
    k=(int)(log(width)/log(2))*(-1);
    *code=malloc((k+1)*sizeof(char));
    if(!(*code))
    {
        printf("malloc erroc!/n");
        return 1;
    }
    fractional=modf(width*pow(2,k),&chance);
    if(abs(fractional)>=1e-16)
    {
        width+=pow(2,-k);
    }
    for(i=0;i<k;i++)
    {
        low*=2;
        (*code)[i]=((int)low)%2+'0';
    }
    (*code)[k]='/0';
    return 0;
}

int set_element_name(char *name)
{
    if(!name)
    {
        printf("pointer is NULL!/n");
        return 1;
    }
    *name=getchar();
    while(getchar()!='/n')
    {
        ;
    }
    return 0;
}

int set_element_chance(double *chance)
{
    if(!chance)
    {
        printf("pointer is NULL!/n");
        return 1;
    }
    scanf("%lf",chance);
    while(getchar()!='/n')
    {
        ;
    }
    return 0;
}

int check_elements(element_set *set)
{
    int i;
    double total=0;
    if(!set)
    {
        printf("pointer is NULL!/n");
        return 1;
    }
    for(i=0;i<set->num;i++)
    {
        total+=set->chance[i];
    }
    if(total!=1)
    {
        return 1;
    }
    else
    {
        return 0;
    }
}

int print_elements_info(element_set *set)
{
    int i;
    if(!set)
    {
        printf("pointer is NULL!/n");
        return 1;
    }
    for(i=0;i<set->num;i++)
    {
        printf("%d:name %c chance %g/n",i+1,set->name[i],set->chance[i]);
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值