正儿八经的数据压缩小课堂——从C++看词典编码之LZW编码

本文深入浅出地介绍了数据压缩中的LZW编码,解释了词典编码的概念,强调了LZW编码中解码端如何自动生成解码词典。文章通过实例分析了编码与解码过程,并探讨了压缩效率问题,指出在某些情况下,LZW编码可能因词典占用体积而降低压缩效果。
摘要由CSDN通过智能技术生成

正儿八经的数据压缩小课堂——从C++看词典编码之LZW编码


前言

什么是编码?我们为什么要编码?要理解这个听上去很高大上的玩意儿其实并不困难——
简单地说,编码是人类利用信息对象(比如数据)的统计特性等特性,来尽可能地压缩对象在传输过程中的体量!以此,来实现本来不可能实现的信息传输过程,还可以节约成本!爽!
今天我们要了解的LZW编码,属于编码大家庭中,词典编码的一种。


一、词典编码

1 通用编码的概念

通用编码的实用性更强、范围更广——管你是什么糟心的实际应用情境,我都能统统“通用”!
许多场合无法观察信源的统计特性,或者可观察但统计特性有变化。对这些数据进行压缩编码的技术统称为通用编码技术。

2 词典编码的思路

常见的数据文件,比如文本、图像、视音频、源代码中,通常都含有大量的重复字符。如果用一些简单的代号代替这些字符串,就可以实现压缩!
字符串与代号的对应表,就是词典。
LZW初始会有一个默认的字典,包含了所有256个8bit字符,单个字符的记号就是它自身,用数字表示就是ASCII值。在此基础上,编码过程中加入的新的记号的映射,从256开始,称为扩展表(Extended Dictionary)。↓
在这里插入图片描述
在这里插入图片描述
不管词典里单个词条中的字符串有多长,最后对应(映射)的都是一个定长的码字!

3 词典解码的思路

LZW编码与LZ77、LZSS等其他传统词典编码的最大区别就在于,这种方法在解码时,解码端会仿照编码端进行编码时的过程,自行生成一本“解码词典”。

在这里插入图片描述
重点来了各位,在上图的例子中,当解码进行到259(解码端收到259时),解码端是懵逼的。为什么?当前解码端的字典里还没有编到259这一项!是的,解码端总是比编码端“延后”一步!
那么怎么办呢?不用担心,首先,我们只要逆向思考一下就会知道,什么时候会出现这种情况——那就是在编码端,当一个词条被录入后,它在下一步里马上就被用到!
比如例子里的:

  1. pw1 ab cw1 a 此时aba录入词典,成为259号词条。
  2. pw2 a cw2 b 此时ab在词典里,继续读下一个字符:pw3 ab cw3 a 此时aba也在词典里!刚刚写进去的,所以这时编码端会直接出一个259给解码端!

通过以上进程,这个问题就好办了!在解码端,我们将会知道这个所谓259号的“未知词条”,它作为一个刚建立就马上被用到的词条,它一定是等于(前一个词条+前一个词条的首字符)!

259:aba = 256:ab + a

为啥捏?看我慢慢道来:
——因为“马上被调用”,所以259是衔接在256尾巴后面的,
ab aba
它的(作为词条被首次正式引用时的)头部的首字符
ab (a)ba
等于(作为词条首次出现被编入词典时的,注意,这和上面不一样!)的尾部的最后一个字符,
ab(a) ba
(其实就是这个a从cw1移动到pw2了哈哈)也就是说,259是个回文形式!(1)
——又因为259的建立就是=前一个词条256的整个词条+下一个单字符的码字(不用纠结,新建词条的最后一个码字一定是一个单字符!)(2)
那么由(1)+(2)可得,这条新建的词条259,就等于(前一个词条+前一个词条的首字符)!

简单版:未知词条=前一个传过来的词条+它的首字符,完事儿。

二、代码注释

/*
 * Definition for LZW coding 
 *
 * vim: ts=4 sw=4 cindent nowrap
 */
#include <stdlib.h>
#include <stdio.h>
#include "bitio.h"
#define MAX_CODE 65535
#pragma warning(disable:4996) 

struct {
   
	int suffix;
	int parent, firstchild, nextsibling;
} dictionary[MAX_CODE+1];

int next_code;
int d_stack[MAX_CODE]; // stack for decoding a phrase

#define input(f) ((int)BitsInput( f, 16))
#define output(f, x) BitsOutput( f, (unsigned long)(x), 16)

int DecodeString( int start, int code);
void InitDictionary( void);


void PrintDictionary( void){
   
	int n;
	int count;
	for( n=256; n<next_code; n++){
   
		count = DecodeString( 0, n);
		printf( "%4d->", n);
		while( 0<count--) printf("%c", (char)(d_stack[count]));
		printf( "\n");
	}
	printf("\n");
}
/*打印出自定义的字典*/

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值