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

LZW编码

时间:2019-10-31 13:31:05      阅读:509      评论:0      收藏:0      [点我收藏+]

标签:def   返回   img   yun   end   自身   代码   lease   基本   

原文:https://segmentfault.com/a/1190000011425787?utm_source=tag-newest

LZW 算法引入

  • 核心思想:把出现过的字符串映射到记号上,这样就可能用较短的编码来表示长的字符串,实现压缩

  • 比如对于字符串 ABABAB 可以看到字串 AB 在后面重复了,就可以用一个特殊的记号表示 AB ,比如使用 2,原来的字符串就表示为 AB22 ,那么 2 就可以称为 AB 的记号

  • 那么如果规定 0 表示 A,1 表示 B,实际上最后得到的压缩后的数据为一个记号流 0122 ,这样就有了一个记号和字符串的映射表,即字典

  • 如下:

    技术图片

  • 压缩后的编码 0122 ,根据字典就可以解码为原字符了

  • 但是在真正的 LZW 中,A 和 B 是用 ASCII 码表示的

  • LZW 初始会有一个默认的字典,包含了所有 256 个 8 bit 字符,单个字符的记号就是它自身,用数字表示就是 ASCII 值

  • 在编码过程中加入的新的记号的映射,从256开始,称为扩展表

字典生成

  • 为什么第一个 AB 不也用 2 表示?
  • LZW 有一个核心思想:压缩后的编码是自解释的
  • 字典是不会被写进压缩文件的,在解压缩的时候,一开始字典里除了默认的 0->A 和 1->B 之外并没有其它映射
  • 2->AB 是在解压缩的过程中一边加入的。这就要求压缩后的数据自己能告诉解码器,完整的字典,例如2->AB,是如何生成的,在解码的过程中还原出编码时用的字典
  • ABABAB 编码过程:
    1. 遇到 A,用 0 表示,编码 0
    2. 遇到 B,用 1 表示,编码 1
    3. 发现子串 AB,添加映射 2->AB 到字典
    4. 遇到 AB,用 2 编码
  • 可以看出最前面的 A 和 B 是用来生成表项 2->AB 的,所以它们必须被保留在压缩编码里,作为表项 2->AB 第一次生成的地方
  • 在解码 0122 的时候,解码器首先通过 01 直接解析出最前面 A 和 B,并且生成表项 2->AB,这样才能将后面出现的 2 都解析为 AB
  • 编码和解码都是从前往后步步推进的,同时生成字典,所以解码的过程也是一个不断还原编码字典的过程。解码器一边解码,向后推进,一边在之前已经解出的原始数据上重现编码的过程,构建出编码时用的字典。

LZW 算法详解

编码算法

  • 编码器从原字符串不断地读入新的字符,并试图将单个字符或字符串编码为记号
  • 这里我们维护两个变量,一个是 P (Previous),表示手头已有的,还没有被编码的字符串,一个是 C (current),表示当前新读进来的字符
  • 算法

    1. 初始状态,字典里只有所有的默认项,例如 0->a,1->b,2->c。此时P 和 C都是空的
    2. 读入新的字符 C,与 P 合并形成字符串 P+C
    3. 在字典里查找 P+C,
      1. 如果 P+C 在字典里,P=P+C
      2. 如果 P+C 不在字典里,将 P的记号输出;在字典中为 P+C建立一个记号映射;更新 P=C
    4. 返回步骤 2 重复,直到读完所有字符
  • P 是当前维护的,可以被编码为记号的子串。注意 P 是可以被编码为记号,但还并未输出。

  • 新的字符 C 不断被读入并添加到 P 的尾部,只要 P+C 仍然能在字典里找到,就不断增长更新 P=P+C,这样就能将一个尽可能长的字串 P 编码为一个记号,这就是压缩的实现

编码例子

  • 压缩 ababcababac

  • 初始状态字典:

    技术图片

  • 开始编码

    技术图片

  • 结果为 0132372

  • 注意编码过程中的第 3-4 步,第 7-8步 以及8-10步,子串 P 发生了增长,直到新的 P+C 无法在字典中找到,则将当前的 P 输出,P 则更新为单字符 C,重新开始增长

LZW 编码 Python 实现

下面的代码是用 0->A,1->B,2->C,作为基本编码表的

s = input("Please input a string: ")

def init(s):
    dict = {}
    tmp = []
    for i in s:
        if i not in tmp:
            tmp.append(i)
    # print(tmp)
    j = 0
    for i in range(len(tmp)):
        t = str(j)
        dict[tmp[i]] = t
        j = j + 1
    # print(dict)
    return dict

def encoding(s):
    r = []
    table = init(s)
    P = ''
    for i in range(len(s)):
        C = s[i]
        t = P+C
        if t in table.keys():
            P = t
            continue
        if t not in table.keys():
            # t=AB
            table[t] = str(len(table))
            r.append(table[P])
            P = C
        if i == len(s)-1:
            r.append(table[s[i]])
    print("After compress: " + ''.join(r))
    print("coding table is: ")
    print(table)

encoding(s)

LZW编码

标签:def   返回   img   yun   end   自身   代码   lease   基本   

原文地址:https://www.cnblogs.com/peri0d/p/11770450.html

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