用python实现的LZW算法

  以前学习了一下GIF的LZW算法,不过只是学习了一下(见我以前的那篇博文《LZW for GIF算法原理和实现》),没有实践,也没有看看效果到底怎么样,因为现在ZIP库很多,基本上不需要自己写压缩算法了,LZW的压缩效果也比不上它们。不过最近有个嵌入式系统上的数据记录需求,希望把运行过程中采集的数据都记录下来,但是存储空间比较有限,处理器的能力也比较有限,是266兆的PPC,所以不能使用复杂的算法了,于是又想起LZW算法来,首先是采集的数据具有短时间内大量重复的特点,可以用简单的算法就达到很好的效果,其次这个算法处理得好的话很省资源,至于压缩比则是其次的考虑。

  为了验证一下算法的正确性和效果,先用python实现了一下算法。由于只是验证算法,所以不考虑效率,只追求编程简单。用Python实现起来还真是方便,如果不进行位紧缩的话,二十多行代码就搞定了,拿几个文件试了下压缩和解压,一个140多K的cpp程序,可以压到33K多,用一个1兆多的软盘映像文件,可以压到一半左右,拿txt的《三国演义》,则只有70%了(不过rar也只能压到50%多)。全部文件解压出来和原文件二进制比较完全一致,证明了算法的正确性。

  实践表明选用的最大位宽越大压缩率越高,但是内存开销和时间开销都最大,而且由于最大位宽比较大,进行位紧缩后效果不明显,而14位的最大位宽综合效果最理想。如果是在嵌入式环境下使用的话,使用小一点的最大位宽开销要小一些,不过不要小于12位。

  有了这个Python版本,接下来准备用C语言再实现一遍的时候就有参考了。

# -*- coding: gbk -*- def LZW ( inStr,narrow=False,bits=14): '''使用LZW压缩算法压缩。 narrow为True时输出字节流位紧缩 默认最大位宽14位,允许范围12~16位''' if isinstance(inStr,str): inStr=list(inStr) for i in range(len(inStr)): inStr[i]=ord(inStr[i]) sOutStr=[256] #先放一个 开始&清除 标记 mTagMap={} #字典 iTagCurrent=258 #当前的标记总数 0~255 标记256 为begin & clear , 257 为end iBitsLen=9 iTag=inStr[0] #当前标记 ii=0 cTemp=0 if bits>16 or bits<12: return None iMaxLen=(1<<bits)-1 #最多允许的标记数,由位宽决定 for ii in range(1,len(inStr)): cChar=inStr[ii] cTemp=(iTag<<8)+cChar #(前缀 后缀) if cTemp in mTagMap: #该(前缀 后缀)已存在 iTag=mTagMap[cTemp] #取出其标记 else: #不存在 sOutStr.append(iTag) #将前缀放入输出流 mTagMap[cTemp]=iTagCurrent iTagCurrent+=1 #增加一个标记,并放入字典 iTag=cChar #当前标记为后缀 if iTagCurrent>=iMaxLen: #如果到达了最大标记数,清除字典,从头开始 sOutStr.append(256) mTagMap={} iTagCurrent=258 if iTag!=0: sOutStr.append(iTag) sOutStr.append(257) #放入结束标记 if narrow: #位紧缩 return Narrow(sOutStr) else: return sOutStr def Narrow (sOutStr): sOutN=[] iTemp=0 BitLeft=0 nowBit=9 #当前位宽 nowStag=1<<nowBit #当前位宽允许的标记数 nowTagCount=258 for cChar in sOutStr: iTemp=iTemp+(cChar<<BitLeft) nowTagCount+=1 BitLeft+=nowBit if cChar==256: nowBit=9 nowStag=1<<nowBit nowTagCount=258 if nowTagCount>=nowStag: nowBit+=1 nowStag=1<<nowBit while BitLeft>=8: sOutN.append(iTemp&0xff) iTemp=iTemp>>8 BitLeft-=8 if BitLeft>0: sOutN.append(iTemp) return sOutN def UnNarrow (inStr): sOut=[] iTemp=0 BitLeft=0 nowBit=9 nowStag=1<<nowBit mask=nowStag-1 nowTagCount=258 for cChar in inStr: iTemp=iTemp+(cChar<<BitLeft) BitLeft+=8 if BitLeft>=nowBit: cTemp=iTemp&mask iTemp=iTemp>>nowBit BitLeft-=nowBit sOut.append(cTemp) nowTagCount+=1 if nowTagCount>=nowStag: nowBit+=1 nowStag=1<<nowBit mask=nowStag-1 if cTemp==256: nowBit=9 nowStag=1<<nowBit mask=nowStag-1 nowTagCount=258 if BitLeft>0: sOut.append(iTemp) return sOut def deTag ( mTagMap,nowTag,outStr): '''将一个标记转化为元字符序列,并放入到输出流中''' if nowTag>=0: sTemp=[] while nowTag>255: pair=mTagMap[nowTag] sTemp.append(pair[1]) nowTag=pair[0] sTemp.append(nowTag) sTemp.reverse() outStr+=sTemp return nowTag def UnLZW ( inStr , narrow=False): if narrow: inStr=UnNarrow(inStr) mTagMap={} outStr=[] nowTagCount=258 sTemp=[] nowTag=-1 for cChar in inStr: if cChar==256: if nowTag>=0: deTag(mTagMap,nowTag,outStr) mTagMap={} nowTagCount=258 nowTag=-1 elif cChar==257: if nowTag>=0: deTag(mTagMap,nowTag,outStr) nowTag=-1 return outStr elif nowTag==-1: #刚开始 nowTag=cChar else: pair=[nowTag,0] mTagMap[nowTagCount]=pair nowTagCount+=1 surfix=cChar while surfix>255: if surfix not in mTagMap: print 'Thera are errors in input' return outStr surfix=mTagMap[surfix][0] pair[1]=surfix deTag(mTagMap,nowTag,outStr) nowTag=cChar def fileLZW ( inFile , outFile , bit=14 ): import os fsize=os.stat(inFile)[6] f=os.open(inFile,os.O_BINARY) s=os.read(f,fsize) os.close(f) a=LZW(s,True,bit) f=open(outFile,'wb') outs='' for i in a: outs+=chr(i) f.write(outs) f.close() def fileUnlzw ( inFile , outFile): import os fsize=os.stat(inFile)[6] f=os.open(inFile,os.O_BINARY) s=os.read(f,fsize) a=[] for i in s: a.append(ord(i)) b=UnLZW(a,True) f=open(outFile,'wb') outs='' for i in b: outs+=chr(i) f.write(outs) f.close()

你可能感兴趣的:(算法,python,嵌入式,input,import,pair)