LZW压缩算法

LZW压缩算法是Lempel-Ziv-Welch 3个人共同发明的,简称 LZW 的压缩算法,可以用任何一种语言来实现它.
LZW是GIF图片文件的压缩算法,而且zip压缩的思想也是基于LZW实现的,所以LZW对文本文件具有很好的压缩性能。

LZW压缩算法的基本原理:提取原始文本文件数据中的不同字符,基于这些字符创建一个编码表,然后用编码表中的字符的索引来替代原始文本文件数据中的相应字符,减少原始数据大小。看起来和 调色板 图象的实现原理差不多,但是应该注意到的是,我们这里的编码表不是事先创建好的,而是根据原始文件数据动态创建的,解码时还要从已编码的数据中还原出原来的编码表.

编码表中每一项的大小一般为12位,用来代表一个字符串。这样编码表有2**12=4096项,编码值是0~4095。通常情况下0~255是固定的,用来代表单个字符0~255。而值256通常用来表示开始新的编码表,因为如果编码表的4096项都用完了,而待压缩文件还没有处理完,那么就需要生成新的编码表继续压缩;257表示压缩结束,用来写到压缩文件尾。从258开始,每个值都代表一个字符串(至少2个字符)。
举个例子,有下面的字符串:ababcdefgefg。(a的ascii码是0x61=97)
压缩后的数据是:97 98 258 99 100 101 102 103 263 103。

其中第二个ab被压缩成258,第二个ef被压缩成263,因为这之前在ab和ef第一次出现的时候就已经被按顺序编入到编码表中。

编码项结构为:

struct Lzw
{
    int *code;      //已被编码
    int *prefix;    //编码索引
    char *suffix;   //对应字符
}Lzw,*lp;

编码表只在压缩过程中使用,并不会被写入到最终的压缩文件,大小为

#define TABLESIZE (4099)

1. 初始化编码表,即
    for(i=0; i<TABLESIZE; i++)
    {
        lp->code[i]=-1;
    }

2. 程序读入第一个字符a,到编码表中查找到对应编码97,记录临时前向编码索引prevcode=97,再读入下一个字符b,然后在编码表中查找prev=97、c='b'的编码项,没有找到, 则表明'ab'没有对应的编码项,则把当前prevcode的值--97写入压缩缓存(该缓存最后会被写入压缩文件);再创建新的编码项string_tab[258],且string_tab[258].prev=97,string_tab[258].c='b'。最后更新临时前向编码索引prevcode=当前字符'b'=98。

    prefix=fgetc(InputFile);
    while((suffix=fgetc(InputFile))!=EOF)
    {
        index=HashSearch(prefix,suffix);

        if(lp->code[index]!=-1)
        {
            prefix=lp->code[index];
        }
        else
        {
            if(ccode<=MAXCODE)
            {
                lp->code[index]=ccode++;
                lp->prefix[index]=prefix;
                lp->suffix[index]=suffix;
            }

            OutPut(OutputFile,prefix);
            prefix=suffix;
        }
    }

Lzw压缩算法完整代码

/*============================================================================
 Name        : Exercise.cbp
 Author      : Haier
 Version     : 1.01
 Copyright   : Copyright (c) 2014
 Description : LZE Compress in C, Ansi-style, Compile by Code::Block
 ============================================================================*/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define BITS      (12)
#define HASHSHIFT (BITS-8)
#define MAXVALUE  ((1<<BITS)-1)
#define MAXCODE   (MAXVALUE-1)
#define TABLESIZE (4099)

struct Lzw
{
    int *code;      //已被编码
    int *prefix;    //编码索引
    char *suffix;   //对应字符
}Lzw,*lp;

/**************************************************************************** 
* Function     : OutPut 
* Description  : To encode the index and Record to File 
* Input        : The File to Output,the index
* Return       : void 
*****************************************************************************/  

void OutPut(FILE *OutPutFile,int Code)
{
    static int ob=0;
    static unsigned long obb=0L;

    obb |=(unsigned long)Code<<(32-BITS-ob);
    ob  +=BITS;

    while(ob>=8)
    {
        putc(obb>>24,OutPutFile);
        obb<<=8;
        ob-=8;
    }
}

/**************************************************************************** 
* Function     : HashSearch 
* Description  : Search for the correct index
* Input        : the index,The corresponding characters
* Return       : Index 
*****************************************************************************/

int HashSearch(int prefix,int suffix)
{
    int index,offset;

    index=(suffix<<HASHSHIFT)^prefix;

    if(index==0)
    {
        offset=1;
    }
    else
    {
        offset=TABLESIZE-index;
    }

    while(1)
    {
        if(lp->code[index]==-1)
        {
            return (index);
        }
        if(lp->prefix[index]==prefix && lp->suffix[index]==suffix)
        {
            return (index);
        }

        index-=offset;
        if(index<0)
        {
            index+=TABLESIZE;
        }
    }

}

/**************************************************************************** 
* Function     : Common 
* Description  : handle after failing to open file
* Input        : Filename
* Return       : void 
*****************************************************************************/

void Common(char *FileName)
{
    char TempFileName[25];

    strcpy(TempFileName,"Can't open ");
    strcat(TempFileName,FileName);
    puts(TempFileName);
    exit(1);

}

/**************************************************************************** 
* Function     : Compress 
* Description  : Lzw Compress Algorithm
* Input        : FileName of input ,FileName of Output
* Return       : void 
*****************************************************************************/

void Compress(FILE *InputFile,FILE *OutputFile)
{
    int prefix,suffix,index,ccode=258,i;

    Lzw.code  =malloc(TABLESIZE*sizeof(int));
    Lzw.prefix=malloc(TABLESIZE*sizeof(int));
    Lzw.suffix=malloc(TABLESIZE*sizeof(char));

    if(Lzw.code==NULL || Lzw.prefix==NULL || Lzw.suffix==NULL)
    {
        printf("The EMS memory spill over !");
        exit(1);
    }

    lp=&Lzw;
    for(i=0; i<TABLESIZE; i++)
    {
        lp->code[i]=-1;
    }

    prefix=fgetc(InputFile);
    while((suffix=fgetc(InputFile))!=EOF)
    {
        index=HashSearch(prefix,suffix);

        if(lp->code[index]!=-1)
        {
            prefix=lp->code[index];
        }
        else
        {
            if(ccode<=MAXCODE)
            {
                lp->code[index]=ccode++;
                lp->prefix[index]=prefix;
                lp->suffix[index]=suffix;
            }

            OutPut(OutputFile,prefix);
            prefix=suffix;
        }
    }

    OutPut(OutputFile,prefix);
    OutPut(OutputFile,MAXVALUE);
    OutPut(OutputFile,0);

    free(lp->code);
    free(lp->prefix);
    free(lp->suffix);
}

/**************************************************************************** 
* Function     : main 
*****************************************************************************/

int main(int argc,char *argv[])
{
    FILE *FileOfInput,*FileOfOutput;

    if(argc!=3)
    {
        printf("Usage: Compress FileInput FileOutput !");
        exit(1);
    }

    if((FileOfInput=fopen(argv[1],"rb"))==NULL)
    {
        Common(argv[1]);
    }

    if((FileOfOutput=fopen(argv[2],"wb"))==NULL)
    {
        Common(argv[2]);
    }


    Compress(FileOfInput,FileOfOutput);

    fclose(FileOfInput);
    fclose(FileOfOutput);
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值