Android 字符串压缩效率最高的方式_伪代码


这篇文章主要是想要总结一下LZW的压缩/解压缩算法。因为写的时候花了好长好长的时间才想清楚应该怎么理解这个解压算法。。。

压缩过程(encode)

首先是压缩过程,伪代码如下:


初始化中间寄存器 A = 0
for 每一个字符 K:
    如果 AK 在 字典中:
        A = AK, 进入下一次循环 
    否则: 
        **输出 A 的编码**
        **把 AK 加入字典**
        A = K


注意我们一开始要把字符集的所有单字符加入字典里面做初始化。

压缩的过程非常清晰易懂。但解码过程可能不那么好理解,因此我们在压缩过程中需要注意到1件事:

输出编码A的过程和把新的键值对加入字典是一起发生的

解码过程(decode)

LZW的解码所用的字典和编码所用的字典完全不一样,这也是LZW算法的一个优点所在:不需要存储字典表。注意解码时字典 key 和 value 的类型要互换一下,字典同样需要进行初始化。另外注意到一开始的第一个字符必然能直接解码。

伪代码如下:


// dict[A] = A 所代表的原始字符串
解码第一个字符 K,输出K
令 A = K
for 每一个字符 K:
    如果 K 在 字典中:
        解码输出 K
        把dict[A] + dict[K][0] 作为新的value放入字典          
    K不在字典中: 
        dict[K] 必然是 dict[A] + dict[A][0]
        把新的键值对加入字典
        解码输出K
    不论K在不在字典中,最后都有 A = K


解码过程和编码过程有一定的区别,最大的区别是当前要解的码可能不在字典中。这种情况我们可以这么解释:

K 不在字典中,说明K正是目前最后一个被加到字典中的项。那么我们最后一个加的项是什么呢?

根据编码过程中我们了解到的“输出编码A的过程和把新的键值对加入字典是一起发生的 ”

说明最后加的项正是上一个输出的编码 A 后面紧跟了一个字符。那么这个紧跟的字符是什么呢? 它A输出字符的首字符(因为K的前缀和A的前缀相同,而且这个字符正是A后面紧跟的多余的字符)

希望我写清楚了……

附代码:


def encode(bs):
    dic = {}
    for i in range(128): dic[(i,)] = i
    res = []
    a = []
    index = 128
    for byte in bs:
        ak = a + [byte]
        if tuple(ak) in dic:
            a  = ak
        else:
            res.append(dic[tuple(a)])
            dic[tuple(ak)] = index
            index += 1 
            a = [byte]
    return res

def decode(bs):
    dic = {}
    index = 128
    for i in range(index): dic[i] = [i]

    res= [dic[bs[0]][0]]
    a = bs[0]
    for byte in bs[1:]:
        if byte not in dic:
            new = dic[a] + [dic[a][0]]
            dic[byte] = new
            res += new          
        else:
            res += dic[byte]
            newv = dic[a] + [dic[byte][0]]
            dic[len(dic)]= newv
        a = byte
    return res