LZ77算法
LZ77算法是由 Lempel-Ziv 在1977发明的,也是GBA内置的压缩算法。LZ77算法有许多派生算法(这里面包括 LZSS算法)。它们的算法原理上基本都相同,无论是哪种派生算法,LZ77算法总会包含一个动态窗口(Sliding Window)和一个预读缓冲器(Read Ahead Buffer)。动态窗口是个历史缓冲器,它被用来存放输入流的前n个字节的有关信息。一个动态窗口的数据范围可以从 0K 到 64K,而LZSS算法使用了一个4K的动态窗口。预读缓冲器是与动态窗口相对应的,它被用来存放输入流的前n个字节,预读缓冲器的大小通常在0 – 258 之间。这个算法就是基于这些建立的。用下n个字节填充预读缓存器(这里的n是预读缓存器的大小)。在动态窗口中寻找与预读缓冲器中的最匹配的数据,如果匹 配的数据长度大于最小匹配长度 (通常取决于编码器,以及动态窗口的大小,比如一个4K的动态窗口,它的最小匹配长度就是2),那么就输出一对〈长度(length),距离 (distance)〉数组。长度(length)是匹配的数据长度,而距离(distance)说明了在输入流中向后多少字节这个匹配数据可以被找到。
例如:(假设一个 10个字节的动态窗口, 以及一个5个字节的预读缓冲器)
文本:A A A A A A A A A A A B A B A A A A A
--------------------- =========
动态窗口 预读缓存器
动 态窗口中包含10个A ,这就是最后读取的10个字节。预读缓冲器包含了 B A B A A。编码的第一步就是寻找动态窗口与预读缓存器相似长度大于2的字节部分。在动态窗口中找不到B A B A A,所以B就被按照字面输出。然后动态窗口滑过1个字节,现在暂时输出了一个B。
第二步:A A A A A A A A A A A B A B A A A A A
--------------------- =========
动态窗口 预读缓存器
现 在预读缓冲器包含A B A A A,然后再和动态窗口进行比较。这时,在动态窗口找到了相似长度为2的A B,因此一对〈长度, 距离〉就被输出了。长度(length)是2 并且向后距离也是2,所以输出为<2,2>,然后动态窗口滑过2个字节。现在已经输出了B <2,2>。
第三步:A A A A A A A A A A A B A B A A A A A
--------------------- =========
动态窗口 预读缓存器
继续上面的方法得到输出结果<5,8>。现在已经输出了B <2,2> <5,8>。
最终的编码结果是:A A A A A A A A A A A B <2,2> <5,8>。
但 数组是无法直接用二进制来表示的,LZ77会把编码每八个数分成一组,每组前用一个前缀标示来说明这八个数的属性。比如数据流:A B A C A C B A C A按照LZ77的算法编码为:A B A C<2,2> <4,5>,刚好八个数。按照LZ77的规则,用“0”表示原文输出,“1”表示数组输出。所以这段编码就表示为:00001111B(等于 0FH),因此得到完整的压缩编码表示:F A B A C 2 2 4 5。虽然表面上只缩短了1个字节的空间,但当数据流很长的时候就会突出它的优势,这种算法在zip格式中是经常用到。
除此之外还有很多压缩算法,像霍夫曼编码(Huffman Encoding)等等。这些编码也是非常的著名而且压缩效率极高,不过这些编码的算法相对比较繁琐,规则也很复杂,由于篇幅就不逐一介绍了。如果大家对这方面感兴趣可以到网站相关网站查询资料。
LZ77算法是由 Lempel-Ziv 在1977发明的,也是GBA内置的压缩算法。LZ77算法有许多派生算法(这里面包括 LZSS算法)。它们的算法原理上基本都相同,无论是哪种派生算法,LZ77算法总会包含一个动态窗口(Sliding Window)和一个预读缓冲器(Read Ahead Buffer)。动态窗口是个历史缓冲器,它被用来存放输入流的前n个字节的有关信息。一个动态窗口的数据范围可以从 0K 到 64K,而LZSS算法使用了一个4K的动态窗口。预读缓冲器是与动态窗口相对应的,它被用来存放输入流的前n个字节,预读缓冲器的大小通常在0 – 258 之间。这个算法就是基于这些建立的。用下n个字节填充预读缓存器(这里的n是预读缓存器的大小)。在动态窗口中寻找与预读缓冲器中的最匹配的数据,如果匹 配的数据长度大于最小匹配长度 (通常取决于编码器,以及动态窗口的大小,比如一个4K的动态窗口,它的最小匹配长度就是2),那么就输出一对〈长度(length),距离 (distance)〉数组。长度(length)是匹配的数据长度,而距离(distance)说明了在输入流中向后多少字节这个匹配数据可以被找到。
例如:(假设一个 10个字节的动态窗口, 以及一个5个字节的预读缓冲器)
文本:A A A A A A A A A A A B A B A A A A A
--------------------- =========
动态窗口 预读缓存器
动 态窗口中包含10个A ,这就是最后读取的10个字节。预读缓冲器包含了 B A B A A。编码的第一步就是寻找动态窗口与预读缓存器相似长度大于2的字节部分。在动态窗口中找不到B A B A A,所以B就被按照字面输出。然后动态窗口滑过1个字节,现在暂时输出了一个B。
第二步:A A A A A A A A A A A B A B A A A A A
--------------------- =========
动态窗口 预读缓存器
现 在预读缓冲器包含A B A A A,然后再和动态窗口进行比较。这时,在动态窗口找到了相似长度为2的A B,因此一对〈长度, 距离〉就被输出了。长度(length)是2 并且向后距离也是2,所以输出为<2,2>,然后动态窗口滑过2个字节。现在已经输出了B <2,2>。
第三步:A A A A A A A A A A A B A B A A A A A
--------------------- =========
动态窗口 预读缓存器
继续上面的方法得到输出结果<5,8>。现在已经输出了B <2,2> <5,8>。
最终的编码结果是:A A A A A A A A A A A B <2,2> <5,8>。
但 数组是无法直接用二进制来表示的,LZ77会把编码每八个数分成一组,每组前用一个前缀标示来说明这八个数的属性。比如数据流:A B A C A C B A C A按照LZ77的算法编码为:A B A C<2,2> <4,5>,刚好八个数。按照LZ77的规则,用“0”表示原文输出,“1”表示数组输出。所以这段编码就表示为:00001111B(等于 0FH),因此得到完整的压缩编码表示:F A B A C 2 2 4 5。虽然表面上只缩短了1个字节的空间,但当数据流很长的时候就会突出它的优势,这种算法在zip格式中是经常用到。
除此之外还有很多压缩算法,像霍夫曼编码(Huffman Encoding)等等。这些编码也是非常的著名而且压缩效率极高,不过这些编码的算法相对比较繁琐,规则也很复杂,由于篇幅就不逐一介绍了。如果大家对这方面感兴趣可以到网站相关网站查询资料。