`

LZW字典压缩

阅读更多

       首先谈谈我对压缩这个词的理解吧。在我看来,压缩=代码+协议。而这二者中,我认为协议比代码更重要,协议是整个压缩的灵魂。就拿哈夫曼压缩法来说,它的协议简单来说就是为待压缩文件中出现过的每个字符设置一个编码,头文件中存储了每个编码对应的字符信息。显然,哈夫曼压缩中的头文件就是我们定下的压缩协议。(今天主要谈LZW压缩法,因此哈夫曼压缩的具体原理就不做过多的说明了。)
        谈到LZW字典压缩,好多同学觉得好高深,这就错了。举个简单的例子,读一篇英语文章,或者一篇英语巨著,里边有好多的单词和句子是重复的,如果我们用一个特定的符号来代替整个单词或句子,那么,节省的空间是相当可观的。

        这就是字典压缩的最初构想。

        想法有了,现在要做的就是定一个协议。这个协议要达到的目标很简单:1)能压缩文件。2)能把压缩文件翻译成原文件。至于压缩效果,那是后期工作。
        先考虑编码问题,0~255是肯定不能用的,于是选取了256~65535,再大了会使编码的长度加倍而字典也不需要那么大。然后要思考怎样使文件中的符号跟编码一一对应,而且字典压缩是没有头文件的,这意味着压缩后的文件可以自己生成字典进行解压。
          在看压缩的过程之前先了解几个名词。前缀:对于每一个词,都拆分成两部分,前边的一个完整的个体(单独的一个字符或者已经写进字典的一个词的编码)叫做前缀,相应的“后缀”就很明了了。
          OK,现在让我们一起来了解一下创建字典的算法(以压缩字符串“ababbacb”为例):

第几步 前缀 后缀  词  查找  输出  编码
 1    a  (,a)      
 2  a  b  (a,b)  no  a  256
 3  b  a  (b,a)  no  b  257
 4  a  b  (a,b)  yes    
 5  256  b  (256,b)  no  256  258
 6  b  a  (b,a)  yes    
 7  257  c  (257,c)  no  257  259
 8  c  b  (c,b)  no  c  260

        协议定好了,现在开始代码实现。

        节点类很简单,其功能是定义两个属性:前缀(first),后缀(end)

public class Node {
	int  frist ;
	int  end;
	public Node(){}
	public Node(int frist,int end){
		this.frist = frist;
		this.end = end;
	}
}

            然后是字典类,先创建一个链表:

public class Dictionary {
	public List<Node> list = new ArrayList<Node>();
}

           将链表的0~255的节点按ASCII初始化:

public Dictionary(){
	for(int i=0;i<256;i++){
		Node node = new Node();
		node.frist = i;
		this.list.add(node);
	}
	
}

         向链表中添加节点:

public void add(int frist,int end){
	Node node = new Node(frist, end);
	list.add(node);
}
	

          获取给定数据的结点的索引,若字典中存在,则返回索引,若不存在返回-2:

public int getIndex(int frist,int end){
	for(int i=0;i<list.size();i++){
		Node node = list.get(i);
		if(node.frist==frist  &&  node.end==end){
			return i;
		}
	}
	return -2;
}

          字典设置完成了,开始实现压缩。

                1.根据地址创建输入输出流。path:要压缩的文件的地址;newpath:  压缩后文件存放的地址

                2.循环进行压缩,直到文件末尾

                    1)如果字典中存在

                    2)如果字典中不存在

                    3)后续处理工作

                    4)如果字典满了,字典清空,做标记,创建新的字典

                    5)到了文件结尾,做标记,翻译

                    6)异常处理

Dictionary dic;
	public void compressFile(String path, String newpath) {
		dic = new Dictionary();
		try {
			File file = new File(path);
			DataInputStream dis = new DataInputStream(new FileInputStream(file));
			File newfile = new File(newpath);
			DataOutputStream newdos = new DataOutputStream(new FileOutputStream(newfile));
			int frist = dis.read();
			while (dis.available() > 0) {
				int end = dis.read();
				int index = dic.getIndex(frist, end);
                                //如果链表里边存在
       				if (index != -2) {
					frist = index;
				}
                                // 如果表里不存在该词组
				else {
					newdos.writeChar(frist);
					dic.add(frist, end);
					frist = end;
					if (dic.list.size() >= 65534) {
						newdos.writeChar(65535);
						dic = new Dictionary();
					}
				}
			}
			// 将剩余的输出
			newdos.writeChar(frist);
			//System.out.println(frist);
			/****** 把后续工作做完 ******/
			newdos.writeChar(65535);
			System.out.println("文件压缩完毕!!!");
			dis.close();
			newdos.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

        

         因为压缩文件中是不存储字典的,所以解压时要根据压缩文件和已经翻译好的部分重新创建字典。

         解压=创建字典+翻译+创建字典+翻译+…… 

      

         具体代码实现如下:

        从字典中查询出字符串的方法(C为查询的字符串在字典中的位置,bufStr 用来存储字典中C位置上存储的字符串):

String bufStr = "";
private void getString(int c) {
		if (c > 255) {
			getString(dic.list.get(c).frist);
			getString(dic.list.get(c).end);
		} else {
			bufStr += (char) c;
		}
}

        准备工作完成,开始解压。。。

         1.判断,如果是0~255直接翻译

         2.如果是前边创建的字典的内容, 按字典翻译

         3.若不在字典中,则该词很奇葩,它一定与其前缀加前缀的第一个字符相等

         个人认为第三点是解压的精华:String str = bufStr + bufStr.charAt(0);

public void releaseFile(String path, String newpath) {
		try {
			File file = new File(path);
			DataInputStream dis = new DataInputStream(new FileInputStream(file));
			File newfile = new File(newpath);
			DataOutputStream newdos = new DataOutputStream(new FileOutputStream(newfile));
			int frist; 
			int end;
			dic = new Dictionary();
			frist = dis.readChar();
			newdos.write(frist);
			while (frist != 65535) {
				end = dis.readChar();
				if (end == 65535) {
					break;
				}
				if (end <= 255) {
					newdos.write(end);
					dic.add(frist,end);
					frist = end;
				} else {
					if (end<dic.list.size()) {
						getString(end);
						newdos.write(bufStr.getBytes());
						dic.add(frist,(int)bufStr.charAt(0));
						bufStr = "";
						frist = end;
					}
					else {
						getString(frist);
						String str = bufStr + bufStr.charAt(0);
						newdos.write(str.getBytes());
						dic.add(frist, (int)bufStr.charAt(0));
						frist = dic.getIndex(frist, bufStr.charAt(0));
						bufStr = "";
					}
				}
			}
			System.out.println("文件解压完毕");
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

     OK,解压到这里就基本完成了。

     

      这里只是提供了压缩的简单思路,许多细节还未注意到(现在只能压缩英语,中文的还不能压缩成功)。

      为了提高压缩效率,我们可以优化压缩协议,比如说当字典满时,可以选择删除重复使用效率不高的词,复用率自己制定,这样压缩效果会更好,大家一起动手试试吧。

 

4
2
分享到:
评论
3 楼 kentkwan 2013-07-26  
2 楼 文昌平蓝杰 2013-07-25  
1 楼 文昌平蓝杰 2013-07-23  
写的不错,顶一个

相关推荐

    lzw.rar_188473.com._LZW图像压缩_lzw_字典法_无损压缩

    然而,由于动态字典的特性,LZW压缩通常比其他固定编码的压缩算法(如霍夫曼编码)更复杂,也更耗时。 总的来说,LZW图像压缩是一种高效的无损压缩方法,特别适合对图像质量和数据完整性要求高的场景。通过字典法,...

    lzw_lzw_lzw压缩_LZW图像压缩_centralr1l_jpglzw_

    LZW(Lempel-Ziv-Welch)压缩算法是一种数据压缩方法,广泛应用于文本、图像和其他类型的数据。它的核心思想是通过构建一个字典来编码数据,将频繁出现的模式压缩成更短的编码,从而达到数据压缩的目的。LZW算法在...

    基于FPGA的LZW数据压缩算法实现.pdf

    LZW算法的核心思想是构建一个压缩字典,在压缩和解压过程中动态更新。在压缩阶段,通过查找字典中的匹配项来替换原始数据中的字符串,从而实现压缩。而在解压阶段,可以无需附加字典信息地重建原数据,因为字典是...

    lzw.rar_LZW图像压缩_lzw_lzw压缩_lzw压缩c++_图像 压缩

    LZW压缩的C++实现通常涉及数据结构(如链表或哈希表来构建字典)、编码和解码循环以及位操作来处理数据流。由于LZW算法需要动态维护字典,所以编程时需要注意内存管理和效率优化。 总的来说,LZW压缩算法是一种高效...

    lzw_soft.zip_LZW 压缩_Soft!_lzw 压缩 解压_压缩_压缩算法源码

    LZW算法的主要特点是通过构建一个动态的字典来编码输入数据,从而实现数据的高效压缩。 在LZW压缩过程中,首先创建一个初始字典,通常包含所有可能的一字节字符。然后,从输入数据流中读取字符,将这些字符组成一个...

    LZWbianma.rar_LZW编码_X-HDL3_lzw_字典压缩编码_字典编码 压缩

    LZW编码,全称为Lempel-Ziv-Welch编码,是一种无损数据压缩算法,广泛应用于文件压缩,如在GIF图像格式中就采用了LZW编码。此压缩方法主要基于字典查找和动态构建的新字典,通过将输入数据流中的重复模式转化为更短...

    lzw_encode.rar_lzw_lzw encode_lzw压缩_lzw字典

    lzw建立字典,可以对文本数据进行压缩。

    基于字典的编码,介绍lzw等压缩算法

    LZ77依赖于固定长度的查找窗口,而LZW则采用动态字典,这使得LZW通常在压缩效率上优于LZ77。然而,LZW由于其动态字典的特性,实现起来相对复杂,且在某些情况下可能需要更大的内存空间。 总结来说,字典编码是一种...

    VB6 LZW无损压缩可控压缩比的压缩及解压缩程序

    LZW算法通常不直接设置压缩比,而是通过调整字典大小来影响压缩效果。字典越大,压缩率可能越低,但解压缩速度更快;反之,字典越小,压缩率越高,但解压缩可能需要更多时间。在VB6程序中,可能通过参数控制字典的...

    LZW的压缩和解压缩(c++)

    LZW(Lempel-Ziv-Welch)压缩算法是一种数据压缩方法,广泛应用于文本、图像和其他类型的数据。它基于字典编码的概念,通过查找和重复使用先前出现过的字符串来减少数据的存储需求。在C++中实现LZW,我们需要理解...

    LZW数据压缩的程序

    在这个压缩包中,"LZW数据压缩"很可能是包含C语言源代码的文件,你可以通过阅读和分析这些源代码来了解LZW算法的具体实现细节,包括如何构建字典,如何编码和解码,以及如何处理字典重置等步骤。这对于深入理解数据...

    LZW的压缩与解压缩算法的PHP实现.zip

    LZW(Lempel-Ziv-Welch)压缩算法是一种数据压缩方法,广泛应用于文本、图像和其他类型的数据。它基于字典编码的概念,通过查找重复出现的模式来减少数据量,从而实现压缩。在PHP中实现LZW压缩与解压缩算法,我们...

    LZW_压缩算法

    在LZW算法中,主要有三个要素:输入流(原始数据)、输出流(压缩后的代码流)和一个动态更新的字符串表(字典)。 1. **编码流程**: - 字典的大小通常预设为固定长度,例如,对于256级灰度的图像,字典长度可能...

    lzwyasuo.rar_lzw_压缩率 matlab_差分压缩_差分编码_编码压缩率

    本文将深入探讨“lzwyasuo.rar”压缩包中涉及的几个重要知识点:LZW(Lempel-Ziv-Welch)压缩算法、差分编码以及在MATLAB环境中实现这些算法。 首先,LZW压缩算法是一种无损数据压缩方法,由Abraham Lempel、Jacob ...

    LZW.rar_LZW压缩java_lzw_lzw 文件压缩_压缩与解压缩_压缩解压

    LZW(Lempel-Ziv-Welch)压缩算法是一种常用的无损数据压缩方法,尤其在文本和图像数据中表现出色。它通过构建一个字典来查找和编码重复的模式,从而达到压缩数据的目的。在Java中实现LZW压缩与解压缩涉及到以下几个...

    c++ lzw 压缩解压

    在C++中实现LZW压缩,你需要创建一个数据结构(如哈希表或关联数组)来存储字典,同时编写两个函数:一个用于编码,另一个用于输出编码的二进制流。 ```cpp struct Dictionary { std::unordered_map, int&gt; entries...

    lzw 压缩解压缩算法

    **LZW算法的核心思想**是通过构建一个动态的字典来实现数据的压缩。字典在压缩过程中不断更新,初始时包含所有单个字符。当遇到一个未在字典中的新字符串时,就将其添加到字典中,并用其编码替换原始字符串。这一...

    LZW数据压缩算法C++源码

    LZW(Lempel-Ziv-Welch)数据压缩算法是一种广泛应用的无损压缩方法,尤其在文本和图像数据的压缩中显示出高效性。它的基本原理是通过建立一个编码字典来逐步组合和压缩输入的数据流。以下是关于LZW算法的详细解释:...

    Lzw压缩解压缩源代码

    LZW(Lempel-Ziv-Welch)压缩算法是一种数据压缩方法,广泛应用于文本、图像和其他类型的数据。它的核心思想是通过构建一个字典来存储频繁出现的字符串,然后用较短的编码来代替这些字符串,从而实现数据的压缩。在...

    LZW压缩程序C语言

    综上所述,LZW压缩算法是一种基于字典的无损压缩方法,通过动态构建和扩展字典来提高压缩效率。C语言实现的LZW压缩程序需要处理编码、解码、字典同步等多个环节,对C语言编程和位操作有较高要求。同时,压缩效果受...

Global site tag (gtag.js) - Google Analytics