LZW编解码算法实现及编码效率分析

一、编码原理

  • 第二类算法的想法是企图从输入的数据中创建一个“短语词典(dictionary of the
    phrases)”,这种短语可以是任意字符的组合。编码数据过程中当遇到已经在词典中出现的“短语”时,编码器就输出这个词典中的短语的“索引号”,而不是短语本身。这种编码方法被称为 LZW 压缩编码。

  • LZW只输出代表词典中的字符串(String)的码字(code
    word)。这就意味着在开始时词典不能是空的,它必须包含可能在字符流中出现的所有单个字符。即在编码匹配时,至少可以在词典中找到长度为1的匹配串。

二、LZW编码算法的思想

1、算法总体思路

在这里插入图片描述

2、举例说明

假设输入的字符序列为: a a a b b b b b b a a b a a b a aaabbbbbbaabaaba aaabbbbbbaabaaba
编码过程如下:

C P + C P + C是否在字典中 P 字典新增项 输出码字
0 a=0, b=1
a a Y a
a aa N a aa=2 0
a aa Y aa
b aab N b aab=3 2
b bb N b bb=4 1
b bb Y bb
b bbb N b bbb=5 4
b bb Y bb
b bbb Y bbb
a bbba N a bbba=6 5
a aa Y aa
b aab Y aab
a aaba N a aaba=7 3
a aa Y aa
b aab Y aab
a aaba Y aaba 7

输出序列为:0214537

解码:

PW P CW C P + C 字典新增项 输出字符
0 a a a=0, b=1 a
0 a 2 a aa aa=2 aa
2 aa 1 b aab aab=3 b
1 b 4 b bb bb=4 bb
4 bb 5 b bbb bbb=5 bbb
5 bbb 3 a bbba bbba=6 aab
3 aab 7 a aaba aaba=7 aaba
7 aaba aaba

输出字符流为aaabbbbbbaabaaba,与输入字符流一致。

  • 注:如果遇到cw值在字典中查找不到的情况,设c=X,则P+C=P+X,该字符串必不在字典中,将其录入字典,当下一次cw值在字典中查找到该P+X字符串时,取其第一个字符为c,则此c为录入时的P的第一个字符,也即X,故X值即为P的第一个字符。
    即,若cw值不在字典中,则c对应的字符记为P的第一个字符。

三、LZW算法的实现

1、数据结构分析

仍以上述字符串为例,假设输入的字符序列为aaabbbbbbaabaaba

在这里插入图片描述

  • 树是动态建立的,且树中每个节点可能存在多个子节点。因此数据结构应该设计成一个节点可拥有任意个子节点,但无需为其预留空间。
  • 将树驻留在一个节点数组中,每个节点至少有两个字段:一个字符和指向母节点的指针。
  • 数据结构中没有指向子节点的指针,对沿着树从一个节点到其子节点的操作,实现方法如下:
尾缀字符(suffix)
母节点(parent)
第一个孩子节点( firstchild )
下一个兄弟节点(nextsibling)

树用数组dict[ ]表示,数组下标用pointer表示,所以dict[pointer]表示一个节点:
dict[pointer].suffix
dict[pointer].parent
dict[pointer].firstchild
dict[pointer].nextsibling

2、主要功能模块分析

  1. 初始化词典
void InitDictionary( void)
{
   
 int i;
 for( i=0; i<256; i++){
   
  dictionary[i].suffix = i;
  dictionary[i].parent = -1;
  dictionary[i].firstchild = -1;
  dictionary[i].nextsibling = i+1;
 }
 dictionary[255].nextsibling = -1;
 next_code = 256;
}
  1. 查找词典中是否有字符串
int InDictionary( int character, int string_code)
{
   
 int sibling;
 if( 0>string_code) return character;
 sibling = dictionary[string_code].firstchild;
 while( -1<sibling){
   
  if( character == dictionary[sibling].suffix) return sibling;
  sibling = dictionary[sibling].nextsibling;
 }
 return -1;
}
  1. 将新串加入词典
void AddToDictionary( int character, int string_code)
{
   
 int firstsibling, nextsibling;
 if( 0>string_code) return;
 dictionary[next_code].suffix = character;
 dictionary[next_code].parent = string_code;
 dictionary[next_code].nextsibling = -1;
 dictionary[next_code].firstchild = -1;
 firstsibling = dictionary[string_code].firstchild;
 if( -1<firstsibling){
    // the parent has child
  nextsibling = firstsibling;
  while( -1<dictionary[nextsibling].nextsibling ) 
   nextsibling = dictionary[nextsibling].nextsibling;
  dictionary[nextsibling].nextsibling = next_code;
 }else{
   // no child before, modify it to be the first
  dictionary[string_code].firstchild = next_code;
 }
 next_code ++;
}

四、完整代码

lzw.c

#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];</
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值