码迷,mamicode.com
首页 > 其他好文 > 详细

7.8 LZW压缩的实现

时间:2016-07-19 20:26:42      阅读:200      评论:0      收藏:0      [点我收藏+]

标签:

7-10 lzw.c

  1 #include <stdlib.h>
  2 #include <stdio.h>
  3 #define BITS 12 //每个数据项的二进制位数 
  4 #define HASHING_SHIFT BITS-8 //HASH表的移位数 
  5 #define MAX_VALUE (1<<BITS)-1
  6 #define MAX_CODE MAX_VALUE-1 //最大标号 
  7 #define TABLE_SIZE 4099 //HASH表的长度 
  8 typedef struct{
  9     int *code;    //代码
 10     unsigned int *prefix; //前缀
 11     unsigned char *suffix; //后缀
 12 }LZW_DATA;
 13 unsigned char decode_stack[TABLE_SIZE]; //用于保存解压缩后的数据
 14 LZW_DATA lzw1,*lzw;
 15 
 16 void compress(FILE *input,FILE *output); //压缩函数 
 17 void expand(FILE *input,FILE *output); //解压函数 
 18 unsigned int hashsearch(int hash_prefix,unsigned int hash_character); //HASH表搜索函数 
 19 char *decode(unsigned char *buffer,unsigned int code);
 20 unsigned int incode(FILE *input);
 21 void outcode(FILE *output,unsigned int code);
 22 
 23 void compress(FILE *input,FILE *output) //压缩函数 
 24 {
 25     unsigned int curr_code;
 26     unsigned int suffix;   //后缀字符 
 27     unsigned int prefix;   //前缀字符 
 28     unsigned int index;
 29     int i;
 30 
 31     if(!(lzw1.code=malloc(TABLE_SIZE*sizeof(unsigned int)))) //代码值数组 
 32     {
 33         printf("内存分配失败!\n");
 34         exit(0); 
 35     }
 36     if(!(lzw1.prefix=malloc(TABLE_SIZE*sizeof(unsigned int))))//压缩前数据 
 37     {
 38         printf("内存分配失败!\n");
 39         exit(0); 
 40     }    
 41     if(!(lzw1.suffix=malloc(TABLE_SIZE*sizeof(unsigned char))))//压缩后数据 
 42     {
 43         printf("内存分配失败!\n");
 44         exit(0); 
 45     }    
 46     lzw=&lzw1;
 47     curr_code=258; //编译表中的字符串编号从258开始 
 48     for(i=0;i<TABLE_SIZE;i++) //初始化标号数组 
 49         lzw->code[i]=-1;
 50     i=0;
 51     printf("\n开始压缩.");
 52     prefix=getc(input); //从文件读取一个字节 
 53     while((suffix=getc(input))!= (unsigned)EOF) //循环处理输入文件中的内容 
 54     {
 55         if (++i==1000) //处理1000个字节显示一个小数点,表示系统正在处理 
 56         {
 57             i=0;
 58             printf(".");
 59         }
 60         index=hashsearch(prefix,suffix); //在HASH表中查找并返回索引号 
 61         if (lzw->code[index]!=-1)//若该标号存在 
 62             prefix=lzw->code[index];//使用该标号作为前缀 
 63         else{                                            //若标号不存在 
 64             if (curr_code<=(MAX_CODE)){ //标号未超过最大标号 
 65                 lzw->code[index]=curr_code++; //增加一个标号 
 66                 lzw->prefix[index]=prefix;  //保存前缀 
 67                 lzw->suffix[index]=suffix; //保存后缀 
 68             }
 69             outcode(output,prefix); //输出前缀字节的内容 
 70             prefix=suffix;//将后缀作前缀,准备下次循环 
 71         }
 72     }
 73     outcode(output,prefix); //输出前缀 
 74     outcode(output,(MAX_VALUE)); //输出结束标志 
 75     outcode(output,0);   
 76 
 77     free(lzw->code); //释放分配的内存 
 78     free(lzw->prefix);
 79     free(lzw->suffix);
 80 }
 81 
 82 unsigned int hashsearch(int prefix,unsigned int suffix)//HASH表搜索函数 
 83 {
 84     int index;
 85     int offset;
 86     index=(suffix << HASHING_SHIFT)^prefix; //构造HASH地址 
 87     if(index == 0) 
 88         offset=1;
 89     else
 90         offset=TABLE_SIZE-index;
 91     while(1)
 92     {
 93         if(lzw->code[index]==-1) //找到一个空表项 
 94             return(index); //返回HASH地址 
 95         if (lzw->prefix[index]==prefix && lzw->suffix[index]==suffix) //找到目标数据 
 96             return(index); //返回HASH地址 
 97         index-=offset; //处理冲突,调整HASH地址 
 98         if(index<0) index+=TABLE_SIZE; //调整HASH地址 
 99     }
100 }
101 
102 void outcode(FILE *output,unsigned int code) //输出压缩后的字节内容 
103 {
104     static int ob=0; //静态变量,保存已输出数据的二进制位数 
105     static unsigned long obb=0L;//静态变量,保存需输出数据的二进制位数 
106     obb |= (unsigned long) code << (32-BITS-ob); //进行移位合并 
107     ob+=BITS; //增加需输出数据的二进制位 
108     while (ob>=8)  //达到一个字节,则输出 
109     {
110         putc(obb>>24,output); //右移24位,使低字节8位为需要输出的数据 
111         obb<<= 8;  //左移8位,去掉已输入的一个字节数据 
112         ob-=8;    //减去已输出的8位,保留剩余的未输出的位数 
113     }
114     return;
115 }
116 void expand(FILE *input,FILE *output) //解压缩函数 
117 {        
118     unsigned int curr_code;
119     unsigned int suffix;
120     unsigned int prefix;
121     int ch;
122     int i;
123     unsigned char *ps;
124     char *decode(unsigned char *buffer,unsigned int code);
125     
126     if(!(lzw1.code=malloc(TABLE_SIZE*sizeof(unsigned int)))) //代码值数组 
127     {
128         printf("内存分配失败!\n");
129         exit(0); 
130     }
131     if(!(lzw1.prefix=malloc(TABLE_SIZE*sizeof(unsigned int))))//压缩前数据 
132     {
133         printf("内存分配失败!\n");
134         exit(0);                                                       
135     }
136     if(!(lzw1.suffix=malloc(TABLE_SIZE*sizeof(unsigned char))))//压缩后数据 
137     {
138         printf("内存分配失败!\n");
139         exit(0);                                                   
140     }
141     lzw=&lzw1;
142     curr_code=258; //定义标号从258开始 
143     i=0;
144     printf("\n解压缩.");
145     prefix=incode(input);  //读入第一个编码,并初始化字符变量 
146     ch=prefix; //保存前缀到字符变量 
147     putc(prefix,output);      // 输出字符到输出文件上
148     while ((suffix=incode(input))!=(MAX_VALUE)) //循环进行解压缩 
149     {
150         if (++i==1000)    //处理1000个字节就显示一个点 
151         {
152             i=0;
153             printf(".");
154         }
155         if (suffix>=curr_code)//后缀是未定义的标号 
156         {
157             *decode_stack=ch; //保存前缀字符 
158             ps=decode(decode_stack+1,prefix);//调用函数进行解码 
159         }
160         else
161             ps=decode(decode_stack,suffix); //调用解码函数处理后缀 
162         
163         ch=*ps;
164         while(ps>=decode_stack) //循环输出解码的字节 
165             putc(*ps--,output);        
166         if (curr_code<=MAX_CODE) //若标号未超过最大值 
167         {
168             lzw->prefix[curr_code]=prefix; //保存前缀到编译表 
169             lzw->suffix[curr_code]=ch;     //保存后缀到编译表 
170             curr_code++; //标号增加 
171         }
172         prefix=suffix; //后缀作前缀,准备下次的循环 
173     }
174     
175     free(lzw->code); //释放分配的内存 
176     free(lzw->prefix);
177     free(lzw->suffix);  
178 }
179 char *decode(unsigned char *buffer,unsigned int code) //解码函数 
180 {
181     int i=0;
182     while(code>257) //code不是ASCII码字符 
183     {
184         *buffer++ =lzw->suffix[code]; //保存标号到缓冲区 
185         code=lzw->prefix[code]; //取得该标号的前缀 
186         if (i++>=TABLE_SIZE)
187         {
188             printf("内存溢出!\n");
189             exit(1);
190         }
191     }
192     *buffer=code; //将标号放入缓冲区 
193     return(buffer); //返回缓冲区中的内容 
194 }
195 
196 unsigned int incode(FILE *input) //从压缩文件中读取数据 
197 {
198     unsigned int ret;
199     static int ib=0; //静态变量,保存读入数据的二进制位数 
200     static unsigned long ibb=0L; //静态变量,保存已读入数据的二进制位
201     while (ib <= 24) //若数据位数小于24位 
202     {
203         ibb |= (unsigned long) getc(input) << (24-ib); //从文件中获取一个字节,并组合到需输出的二进制位中 
204         ib += 8;
205     }
206     ret=ibb>>(32-BITS); //右移20位二进制数 (32-12)
207     ibb <<= BITS; //再左多12位 
208     ib -= BITS; //减去已返回的位数 
209     return(ret);//返回移位后的数据 
210 }
211 int main(int argc, char *argv[])
212 {
213     FILE *fp1,*fp2;
214     int flag=0;
215     char *op;
216     if(argc!=4) //判断传入参数的数量 
217         flag=1;
218     else{
219         op=argv[1];
220         if ((strcmp(op,"-z")!=0) && strcmp(op,"-e")!=0) flag=1;
221     }
222     if(flag)
223     {
224         printf("使用方法:command -z/-e source dest\n");
225         exit(1); 
226     }
227     if((fp1=fopen(argv[2],"rb"))==NULL) //打开文件出错 
228     {
229         printf("不能打开源文件!\n");
230         exit(1);
231     }
232     if((fp2=fopen(argv[3],"wb"))==NULL) //创建文件出错 
233     {
234         printf("不能创建目标文件!\n");
235         exit(1); 
236     }
237     if(strcmp(op,"-z")==0)
238         compress(fp1,fp2);//调用压缩函数 
239     else
240         expand(fp1,fp2);//调用解压缩函数 
241     fclose(fp1);//释放文件指针 
242     fclose(fp2);
243     return 0;
244 }

 

7.8 LZW压缩的实现

标签:

原文地址:http://www.cnblogs.com/wozixiaoyao/p/5686024.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!