LZW 编解码算法实现与分析

一、实验目的

掌握词典编码的基本原理,用C/C++/Python等语言编程实现LZW解码器并分析编解码算法。

二、实验原理

1.LZW概述

  • LZW 是一种无损数据压缩算法,对于GIF、TIFF格式等文件以及较大规模的英文文本的压缩具有良好的效果,一般可以压缩到原来大小的一半。
  • LZW算法通过建立字典,实现字符重用与编码,适用于source中重复率很高的文本压缩。

2.LZW编码

(1)LZW编码简介

  • LZW的编码思想是不断地从字符流中提取新的字符串,通俗地理解为新“词条”,然后用“代号”也就是码字表示这个“词条”。这样一来,对字符流的编码就变成了用码字去替换字符流,生成码字流,从而达到压缩数据的目的
  • LZW编码是围绕称为词典的转换表来完成的。LZW编码器通过管理这个词典完成输入与输出之间的转换。LZW编码器的输入是字符流,字符流可以是用8位ASCII字符组成的字符串,而输出是用n位(例如12位)表示的码字流。
    在这里插入图片描述

(2)具体执行步骤

  • 步骤1:将词典初始化为包含所有可能的单字符,当前前缀P初始化为空;
  • 步骤2:当前字符C为字符流中的下一个字符;
  • 步骤3:判断缀-符串 P+C是否在词典中
    (1)如果“是”,P = P+C,返回步骤2
    (2)如果“否”
    ①把代表当前前缀P的码字输出到码字流;
    ②把缀-符串 P+C添加到词典;
    ③令P=C(现在的Р仅包含一个字符C)并返回步骤2
  • 步骤4:判断码字流中是否还有码字要译
    (1)如果“是”,就返回到步骤2;
    (2)如果“否”
    ①把代表当前前缀Р的码字输出到码字流;
    ②结束。

3.LZW解码

(1)LZW解码简介

LZW解码算法开始时,译码词典和编码词典相同,包含所有可能的前缀根。解码的核心思想在于解码需要还原出编码时的用的字典。要理解解码的原理,首先需要理解它是如何对应编码的过程的。

解码器的输入是压缩后的数据,即记号流 (Symbol Stream)。类似于编码,我们仍然维护两个变量pW (previous word) 和cW (current word),后缀W的含义是word,实际上就是记号 (Symbol),一个记号就代表一个word,或者说子串。pW表示之前刚刚解码的记号;cW表示当前新读进来的记号。

(2)具体执行步骤

  • 步骤1:在开始译码时词典包含所有可能的前缀根(Root)。
  • 步骤2:CW表示码字流中的第一个码字。
  • 步骤3:输出当前缀-符串 string.cW到码字流。
  • 步骤4:先前码字pW : =当前码字cW;当前码字cW : =码字流中的下一个码字。
  • 步骤5:判断当前缀-符串 string.cW是否在词典中
    (1)如果“是”,则:
    ①把当前缀-符串string.CW输出到字符流。
    ②当前前缀P:=先前缀-符串 string.pW。
    ③当前字符C:=当前前缀-符串 string.cW的第一个字符。
    ④把缀-符串 P+C添加到词典。
    (2)如果“否”,则:
    ①当前前缀P:=先前缀-符串 string.pW。
    ②当前字符C:=当前缀-符串 string.W的第一个字符。
    ③输出缀-符串P+C到字符流,然后把它添加到词典中。
  • 步骤6:判断码字流中是否还有码字要译
    (1)如果“是”,就返回到步骤4。
    (2)如果“否”,结束。

(3)解码过程分析

在这里插入图片描述
编码端向解码端传输的是0~255的词典以及需要解码的数字序列,如下图的97 98 98 256 259 99

此时PW=a,CW=b=C,由于a、b均在词典中,执行步骤5(1),将P+C写入词典,即ab写入词典,对应256
在这里插入图片描述

由于解码端与编码端相比有延迟,编码时刚加入词典的字符串在解码端立即被用到,故会出现解码时当前码字在词典中不存在的情况。 如果出现当前码字CW在词典中不存在时,该如何解决呢?

首先我们思考对应的LZW编码过程:
在这里插入图片描述

  • 如图,当p=a,c=b时,P+C=ab在词典中,故有P=P+C=ab,C=a,得P+C=aba不在字典中,故把P+C缀串组合即组成新字符串aba写入词典,以此类推P=C=a,C=b;P+C=ab在字典,此时P=P+C=ab,C=a,P+C=aba在词典,拓展P=aba,C=c,写入P+C=abac于词典。

经过推理可以发现,编码时呈现如下规律:PW的第一个字符即为CW的最后一个字符。
根据编码的规律,解码时先把PW的第一个字符写为新词条的最后一个字符,与PW字符串组合得出新字符串,可推测解码的新字符串是多少并写入词典。

例如下图的解码过程,解码端CW=259尚不存在于字典中,出现无法解码的情况。观察编码规律可推断,259对应的字符串必为上一个字符串PW=ab加上其第一个字符即a,得出CW=aba,此时对259解码得aba并加入词典。在这里插入图片描述

四、实验过程及代码

1、建立头文件及源文件

在这里插入图片描述

2、编写程序

(1)bitio.h

/*
 * Declaration for bitwise IO
 *
 * vim: ts=4 sw=4 cindent
 */
#ifndef __BITIO__
#define __BITIO__

#include <stdio.h>

typedef struct{
   
	FILE *fp;
	unsigned char mask;
	int rack;
}BITFILE;

BITFILE *OpenBitFileInput( char *filename);
BITFILE *OpenBitFileOutput( char *filename);
void CloseBitFileInput( BITFILE *bf);
void CloseBitFileOutput( BITFILE *bf);
int BitInput( BITFILE *bf);
unsigned long BitsInput( BITFILE *bf, int count);
void BitOutput( BITFILE *bf, int bit);
void BitsOutput( BITFILE *bf, unsigned long code, int count);
#endif	// __BITIO__

(2)bitio.c

/*
 * Definitions for bitwise IO
 *
 * vim: ts=4 sw=4 cindent
 */
#define _CRT_SECURE_NO_WARNINGS
#include <stdlib.h>
#include <stdio.h>
#include "bitio.h"

/*打开二进制输出文件,不存在则新建,存在则覆盖已有文件*/
BITFILE *OpenBitFileInput( char *filename){
   
	BITFILE *bf;
	bf = (BITFILE *)malloc( sizeof(BITFILE));
	if( NULL == bf) return NULL;
	if( NULL == filename)	bf->fp = stdin;
	else bf->fp = fopen( filename, "rb");//以二进制只写的方式打开文件

	if( NULL == bf->fp) return NULL;
	bf->mask = 0x80;
	bf->rack = 0;
	return bf;
}

BITFILE *OpenBitFileOutput( char *filename){
   
	BITFILE *bf;
	bf = (BITFILE *)malloc( sizeof(BITFILE));
	if( NULL == bf) return NULL;
	if( NULL 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值