LZ77压缩算法实验报告
lz77压缩算法java 语言实现

一、介绍LZ77压缩算法是一种常用的无损数据压缩算法,由Abraham Lempel和Jacob Ziv在1977年提出。
该算法通过利用历史数据的重复性,将重复的数据替换为指向历史数据的指针,从而实现对数据的压缩。
在本文中,我们将介绍如何使用Java语言实现LZ77压缩算法,以及对其性能进行分析。
二、实现原理1. 窗口和缓冲区在LZ77压缩算法中,窗口和缓冲区是两个重要的概念。
窗口是一个固定大小的滑动窗口,用于存储历史数据。
缓冲区则是用于存储待压缩的数据。
2. 搜索和编码LZ77算法通过在窗口中搜索与缓冲区匹配的子串,并将匹配的子串用指向窗口中相应位置的指针来表示。
还需要编码匹配长度和偏移量,以实现对数据的压缩。
三、Java语言实现1. 数据结构在Java语言中,我们可以使用字符串来表示待压缩的数据。
我们需要定义一个数据结构来表示LZ77算法中的窗口和缓冲区。
在本文中,我们使用一个双向队列来表示窗口,使用一个字符数组来表示缓冲区。
2. 搜索和匹配在Java语言中,我们可以使用字符串的相关方法来实现在窗口中搜索和匹配子串的功能。
一旦找到匹配的子串,我们就可以得到匹配的长度和偏移量。
3. 编码和解码LZ77算法中的编码过程涉及到将匹配的长度和偏移量转化为指针的形式,并将其与匹配的字符一起输出。
在Java语言中,我们可以利用字符串的拼接和格式化方法来实现编码的过程。
而在解码过程中,我们需要根据指针的形式来还原出原始数据。
四、性能分析1. 时间复杂度在实现LZ77压缩算法时,搜索和匹配是算法的核心步骤。
在Java语言中,字符串的相关操作通常具有较高的时间复杂度。
在实际应用中,我们需要对算法进行优化,以提高搜索和匹配的效率。
2. 空间复杂度在Java语言中,字符串的存储通常占用较多的内存空间。
在LZ77压缩算法中,窗口和缓冲区的存储也会占用一定的内存空间。
在实际应用中,我们需要考虑如何有效地利用内存空间。
LZ77压缩算法详解

gzip 、zlib以及图形格式png,使用的压缩算法都是deflate算法。
从gzip的源码中,我们了解到了defalte 算法的原理和实现。
我阅读的gzip版本为 gzip-1.2.4。
下面我们将要对deflate算法做一个分析和说明。
首先简单介绍一下基本原理,然后详细的介绍实现。
1 gzip 所使用压缩算法的基本原理gzip 对于要压缩的文件,首先使用LZ77算法的一个变种进行压缩,对得到的结果再使用Huffman编码的方法(实际上gzip根据情况,选择使用静态Huffman编码或者动态Huffman编码,详细内容在实现中说明)进行压缩。
所以明白了LZ77算法和Huffman编码的压缩原理,也就明白了gzip的压缩原理。
我们来对LZ77算法和Huffman编码做一个简单介绍。
1.1 LZ77算法简介这一算法是由Jacob Ziv 和 Abraham Lempel 于 1977 年提出,所以命名为 LZ77。
1.1.1 LZ77算法的压缩原理如果文件中有两块内容相同的话,那么只要知道前一块的位置和大小,我们就可以确定后一块的内容。
所以我们可以用(两者之间的距离,相同内容的长度)这样一对信息,来替换后一块内容。
由于(两者之间的距离,相同内容的长度)这一对信息的大小,小于被替换内容的大小,所以文件得到了压缩。
下面我们来举一个例子。
有一个文件的内容如下 其中有些部分的内容,前面已经出现过了,下面用()括起来的部分就是相同的部分。
(http://jiurl.)nease(.net)我们使用 (两者之间的距离,相同内容的长度) 这样一对信息,来替换后一块内容。
(22,13)nease(23,4)(22,13)中,22为相同内容块与当前位置之间的距离,13为相同内容的长度。
(23,4)中,23为相同内容块与当前位置之间的距离,4为相同内容的长度。
由于(两者之间的距离,相同内容的长度)这一对信息的大小,小于被替换内容的大小,所以文件得到了压缩。
lz77编码例题详解(一)

lz77编码例题详解(一)LZ77编码例题详细解释LZ77编码是一种无损数据压缩算法,它可以通过利用数据中的重复部分来减小数据的大小。
下面是一个对LZ77编码的例题进行详细解释。
1. LZ77编码原理LZ77编码的原理是利用前缀编码和后缀编码来表示数据中的重复部分。
具体步骤如下:1.遍历待压缩的数据,从左到右逐个字符进行处理。
2.如果当前字符在之前的字符中没有出现过,则将该字符直接输出。
3.如果当前字符在之前的字符中出现过,则向前查找最长的匹配字符串。
4.将匹配字符串的起始位置和长度编码为前缀编码。
5.将匹配字符串的后一个字符输出。
2. 例题分析下面我们通过一个例题来演示LZ77编码的过程。
待压缩的数据:abcabcabc首先,我们处理第一个字符a。
由于是第一个字符,没有前面的字符,所以直接输出:a。
2.2 第二个字符接下来,我们处理第二个字符b。
由于之前的字符中没有出现过b,所以直接输出:b。
2.3 第三个字符然后,我们处理第三个字符c。
由于之前的字符中没有出现过c,所以直接输出:c。
2.4 第四个字符接下来,我们处理第四个字符a。
此时,我们可以向前查找,发现之前的字符中出现了a,而且前面的字符aba可以与当前的字符a构成重复。
所以我们可以用前缀编码来表示这个匹配。
•匹配字符串的起始位置:向前查找的位置是第一个a,距离当前位置为3。
•匹配字符串的长度:匹配到的字符串长度为1。
所以我们可以用(3, 1)来表示这个匹配,然后输出匹配后的字符a,整体编码为:(3, 1)a。
继续处理第五个字符b。
由于之前的字符中没有出现过b,所以直接输出:b。
2.6 第六个字符然后,我们处理第六个字符c。
由于之前的字符中没有出现过c,所以直接输出:c。
2.7 第七个字符接下来,我们处理第七个字符a。
此时,我们可以向前查找,发现之前的字符中出现了a,而且前面的字符bca可以与当前的字符a构成重复。
所以我们可以用前缀编码来表示这个匹配。
数据压缩实验报告(3篇)

第1篇一、实验目的1. 了解数据压缩的基本原理和方法。
2. 掌握常用数据压缩算法的应用。
3. 分析不同数据压缩算法的性能和适用场景。
二、实验环境1. 操作系统:Windows 102. 编程语言:Python3. 数据压缩工具:Huffman编码、LZ77、LZ78、RLE、JPEG、PNG三、实验内容1. Huffman编码2. LZ77编码3. LZ78编码4. RLE编码5. 图像压缩:JPEG、PNG四、实验步骤1. Huffman编码(1)设计Huffman编码树,计算每个字符的频率。
(2)根据频率构建Huffman编码树,为每个字符分配编码。
(3)将原始数据按照Huffman编码进行编码,得到压缩数据。
(4)解压缩:根据编码表还原原始数据。
2. LZ77编码(1)设计LZ77编码算法,查找匹配的字符串。
(2)将原始数据按照LZ77编码进行编码,得到压缩数据。
(3)解压缩:根据编码表还原原始数据。
3. LZ78编码(1)设计LZ78编码算法,查找匹配的字符串。
(2)将原始数据按照LZ78编码进行编码,得到压缩数据。
(3)解压缩:根据编码表还原原始数据。
4. RLE编码(1)设计RLE编码算法,统计连续字符的个数。
(2)将原始数据按照RLE编码进行编码,得到压缩数据。
(3)解压缩:根据编码表还原原始数据。
5. 图像压缩:JPEG、PNG(1)使用JPEG和PNG工具对图像进行压缩。
(2)比较压缩前后图像的质量和大小。
五、实验结果与分析1. Huffman编码(1)压缩前后数据大小:原始数据大小为100KB,压缩后大小为25KB。
(2)压缩效率:压缩比约为4:1。
2. LZ77编码(1)压缩前后数据大小:原始数据大小为100KB,压缩后大小为35KB。
(2)压缩效率:压缩比约为3:1。
3. LZ78编码(1)压缩前后数据大小:原始数据大小为100KB,压缩后大小为30KB。
(2)压缩效率:压缩比约为3.3:1。
LZ77 压缩算法实验报告 一

LZ77 压缩算法实验报告一、实验内容:使用 C++编程实现 LZ77 压缩算法的实现。
二、实验目的:用 LZ77 实现文件的压缩。
三、实验环境: 1、软件环境:Visual C++ 6.02、编程语言:C++四、实验原理: LZ77 算法在某种意义上又可以称为“滑动窗口压缩”,这是由于该算法将一个虚拟的,可以跟随压缩进程滑动的窗口作为术语字典,要压缩的字符串如果在该窗口中出现,则输出其出现位置和长度。
使用固定大小窗口进行术语匹配,而不是在所有已经编码的信息中匹配,是因为匹配算法的时间消耗往往很多,必须限制字典的大小才能保证算法的效率;随着压缩的进程滑动字典窗口,使其中总包含最近编码过的信息,是因为对大多数信息而言,要编码的字符串往往在最近的上下文中更容易找到匹配串。
五、 LZ77 算法的基本流程:1、从当前压缩位置开始,考察未编码的数据,并试图在滑动窗口中找出最长的匹配字符串,如果找到,则进行步骤2,否则进行步骤 3。
2、输出三元符号组 ( off, len, c )。
其中 off 为窗口中匹配字符串相对窗口边界的偏移,len 为可匹配的长度,c 为下一个字符。
然后将窗口向后滑动 len + 1 个字符,继续步骤 1。
3、输出三元符号组 ( 0, 0, c )。
其中 c 为下一个字符。
然后将窗口向后滑动 len + 1 个字符,继续步骤 1。
代码如下:#include<windows.h>#include<stdio.h>#include<memory.h>#include"lz77.h"//////////////////////////////////////////////////////////////////// out file format:// 0;flag2;buffer;0;flag2;buffer;...flag1;flag2;bufferlast// flag1 - 2 bytes, source buffer block length// if block size is 65536, be zero// flag2 - 2 bytes, compressed buffer length// if can not compress, be same with flag1//////////////////////////////////////////////////////////////////void main(int argc, char* argv[]){/*if (argc != 4){puts("Usage: ");printf(" Compress : %s c sourcefile destfile\n", argv[0]); printf(" Decompress : %s d sourcefile destfile\n", argv[0]); return;} */BYTE soubuf[65536];BYTE destbuf[65536 + 16];FILE* in;FILE* out;/* in = fopen("input.txt", "rb");if (in == NULL){puts("Can't open source file");return;}out = fopen("compress.txt", "wb");if (out == NULL){puts("Can't open dest file");fclose(in);return;}fseek(in, 0, SEEK_END);long soulen = ftell(in);fseek(in, 0, SEEK_SET);CCompressLZ77 cc;WORD flag1, flag2; */int temp;printf("compress(0) or decompress(1)?:");scanf("%d",&temp);if (temp == 0) // compress{in = fopen("input.txt", "rb");if (in == NULL){puts("Can't open source file");return;}out = fopen("compress.txt", "wb");if (out == NULL){puts("Can't open dest file");fclose(in);return;}fseek(in, 0, SEEK_END);long soulen = ftell(in);fseek(in, 0, SEEK_SET);CCompressLZ77cc;WORD flag1, flag2;int last = soulen, act;while ( last > 0 ){act = min(65536, last);fread(soubuf, act, 1, in);last -= act;if (act == 65536) // out 65536 bytesflag1 = 0;else// out last blocksflag1 = act;fwrite(&flag1, sizeof(WORD), 1, out);int destlen = press((BYTE*)soubuf, act, (BYTE*)destbuf);if (destlen == 0) // can't compress the block{flag2 = flag1;fwrite(&flag2, sizeof(WORD), 1, out);fwrite(soubuf, act, 1, out);}else{flag2 = (WORD)destlen;fwrite(&flag2, sizeof(WORD), 1, out);fwrite(destbuf, destlen, 1, out);}}}else if (temp == 1) // decompress{in = fopen("compress.txt", "rb");if (in == NULL){puts("Can't open source file");return;}out = fopen("decompress.txt", "wb");if (out == NULL){puts("Can't open dest file");fclose(in);return;}fseek(in, 0, SEEK_END);long soulen = ftell(in);fseek(in, 0, SEEK_SET);CCompressLZ77cc;WORD flag1, flag2;int last = soulen, act;while (last > 0){fread(&flag1, sizeof(WORD), 1, in);fread(&flag2, sizeof(WORD), 1, in);last -= 2 * sizeof(WORD);if (flag1 == 0)act = 65536;elseact = flag1;last-= flag2 ? (flag2) : act;if (flag2 == flag1){fread(soubuf, act, 1, in);}else{fread(destbuf, flag2, 1, in);if (!cc.Decompress((BYTE*)soubuf, act, (BYTE*)destbuf)){puts("Decompress error");fclose(in);fclose(out);return;}}fwrite((BYTE*)soubuf, act, 1, out);}}else{puts("Usage: ");printf(" Compress : %s c sourcefile destfile\n", argv[0]);printf(" Decompress : %s d sourcefile destfile\n", argv[0]);}fclose(in);fclose(out);}//////////////////////////////// LZ77.h//////////////////////////////// 使用在自己的堆中分配索引节点,不滑动窗口// 每次最多压缩65536 字节数据// 的优化版本#ifndef_WIX_LZ77_COMPRESS_HEADER_001_#define_WIX_LZ77_COMPRESS_HEADER_001_// 滑动窗口的字节大小#define_MAX_WINDOW_SIZE65536class CCompress{public:CCompress() {};virtual ~CCompress() {};public:virtual int Compress(BYTE* src, int srclen, BYTE* dest) = 0;virtual BOOL Decompress(BYTE* src, int srclen, BYTE* dest) = 0;protected:// tools/////////////////////////////////////////////////////////// CopyBitsInAByte : 在一个字节范围内复制位流// 参数含义同CopyBits 的参数// 说明:// 此函数由CopyBits 调用,不做错误检查,即// 假定要复制的位都在一个字节范围内void CopyBitsInAByte(BYTE* memDest, int nDestPos,BYTE* memSrc, int nSrcPos, int nBits);////////////////////////////////////////////////////////// CopyBits : 复制内存中的位流// memDest - 目标数据区// nDestPos - 目标数据区第一个字节中的起始位// memSrc - 源数据区// nSrcPos - 源数据区第一个字节的中起始位// nBits - 要复制的位数// 说明:// 起始位的表示约定为从字节的高位至低位(由左至右)// 依次为0,,... , 7// 要复制的两块数据区不能有重合void CopyBits(BYTE* memDest, int nDestPos,BYTE* memSrc, int nSrcPos, int nBits);//////////////////////////////////////////////////////////////// 将DWORD值从高位字节到低位字节排列void InvertDWord(DWORD* pDW);/////////////////////////////////////////////////////////////// 设置byte的第iBit位为aBit// iBit顺序为高位起从记数(左起)void SetBit(BYTE* byte, int iBit, BYTE aBit);////////////////////////////////////////////////////////////// 得到字节byte第pos位的值// pos顺序为高位起从记数(左起)BYTE GetBit(BYTE byte, int pos);////////////////////////////////////////////////////////////// 将位指针*piByte(字节偏移), *piBit(字节内位偏移)后移num位void MovePos(int* piByte, int* piBit, int num);/////////////////////////////////////////////////////////// 取log2(n)的upper_boundint UpperLog2(int n);/////////////////////////////////////////////////////////// 取log2(n)的lower_boundint LowerLog2(int n);};class CCompressLZ77 : public CCompress{public:CCompressLZ77();virtual ~CCompressLZ77();public://///////////////////////////////////////////// 压缩一段字节流// src - 源数据区// srclen - 源数据区字节长度, srclen <= 65536// dest - 压缩数据区,调用前分配srclen字节内存// 返回值> 0 压缩数据长度// 返回值= 0 数据无法压缩// 返回值< 0 压缩中异常错误int Compress(BYTE* src, int srclen, BYTE* dest);/////////////////////////////////////////////// 解压缩一段字节流// src - 接收原始数据的内存区, srclen <= 65536// srclen - 源数据区字节长度// dest - 压缩数据区// 返回值- 成功与否BOOL Decompress(BYTE* src, int srclen, BYTE* dest);protected:BYTE* pWnd;// 窗口大小最大为64k ,并且不做滑动// 每次最多只压缩64k 数据,这样可以方便从文件中间开始解压// 当前窗口的长度int nWndSize;// 对滑动窗口中每一个字节串排序// 排序是为了进行快速术语匹配// 排序的方法是用一个k大小的指针数组// 数组下标依次对应每一个字节串:(00 00) (00 01) ... (01 00) (01 01) ...// 每一个指针指向一个链表,链表中的节点为该字节串的每一个出现位置struct STIDXNODE{WORD off; // 在src中的偏移WORD off2; // 用于对应的字节串为重复字节的节点// 指从off 到off2 都对应了该字节串WORD next; // 在SortHeap中的指针};WORD SortTable[65536]; // 256 * 256 指向SortHeap中下标的指针// 因为窗口不滑动,没有删除节点的操作,所以// 节点可以在SortHeap 中连续分配struct STIDXNODE* SortHeap;int HeapPos; // 当前分配位置// 当前输出位置(字节偏移及位偏移)int CurByte, CurBit;protected:////////////////////////////////////////// 输出压缩码// code - 要输出的数// bits - 要输出的位数(对isGamma=TRUE时无效)// isGamma - 是否输出为γ编码void_OutCode(BYTE* dest, DWORD code, int bits, BOOL isGamma);///////////////////////////////////////////////////////////// 在滑动窗口中查找术语// nSeekStart - 从何处开始匹配// offset, len - 用于接收结果,表示在滑动窗口内的偏移和长度// 返回值- 是否查到长度为或以上的匹配字节串BOOL_SeekPhase(BYTE* src, int srclen, int nSeekStart, int* offset, int* len);///////////////////////////////////////////////////////////// 得到已经匹配了个字节的窗口位置offset// 共能匹配多少个字节inline int_GetSameLen(BYTE* src, int srclen, int nSeekStart, int offset);//////////////////////////////////////////// 将窗口向右滑动n个字节inline void_ScrollWindow(int n);// 向索引中添加一个字节串inline void_InsertIndexItem(int off);// 初始化索引表,释放上次压缩用的空间void_InitSortTable();};#endif// _WIX_LZW_COMPRESS_HEADER_001_ //////////////////////////////// LZ77.CPP//////////////////////////////#include<windows.h>#include<stdio.h>#include<memory.h>#include<crtdbg.h>#include"lz77.h"///////////////////////////////////////////////////////// // 取log2(n)的upper_boundint CCompress::UpperLog2(int n){int i = 0;if (n > 0){int m = 1;while(1){if (m >= n)return i;m <<= 1;i++;}}elsereturn -1;}// UpperLog2////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // 取log2(n)的lower_boundint CCompress::LowerLog2(int n){int i = 0;if (n > 0){int m = 1;while(1){if (m == n)return i;if (m > n)return i - 1;m <<= 1;i++;}}elsereturn -1;}// LowerLog2/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 将位指针*piByte(字节偏移), *piBit(字节内位偏移)后移num位void CCompress::MovePos(int* piByte, int* piBit, int num) {num += (*piBit);(*piByte) += num / 8;(*piBit) = num % 8;}// MovePos////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 得到字节byte第pos位的值// pos顺序为高位起从记数(左起)BYTE CCompress::GetBit(BYTE byte, int pos){int j = 1;j <<= 7 - pos;if (byte & j)return 1;elsereturn 0;}// GetBit//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 设置byte的第iBit位为aBit// iBit顺序为高位起从记数(左起)void CCompress::SetBit(BYTE* byte, int iBit, BYTE aBit){if (aBit)(*byte) |= (1 << (7 - iBit));else(*byte) &= ~(1 << (7 - iBit));}// SetBit////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 将DWORD值从高位字节到低位字节排列void CCompress::InvertDWord(DWORD* pDW){union UDWORD{ DWORD dw; BYTE b[4]; };UDWORD* pUDW = (UDWORD*)pDW;BYTE b;b = pUDW->b[0]; pUDW->b[0] = pUDW->b[3]; pUDW->b[3] = b;b = pUDW->b[1]; pUDW->b[1] = pUDW->b[2]; pUDW->b[2] = b; }// InvertDWord//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// CopyBits : 复制内存中的位流// memDest - 目标数据区// nDestPos - 目标数据区第一个字节中的起始位// memSrc - 源数据区// nSrcPos - 源数据区第一个字节的中起始位// nBits - 要复制的位数// 说明:// 起始位的表示约定为从字节的高位至低位(由左至右)// 依次为0,,... , 7// 要复制的两块数据区不能有重合void CCompress::CopyBits(BYTE* memDest, int nDestPos,BYTE* memSrc, int nSrcPos, int nBits){int iByteDest = 0, iBitDest;int iByteSrc = 0, iBitSrc = nSrcPos;int nBitsToFill, nBitsCanFill;while (nBits > 0){// 计算要在目标区当前字节填充的位数nBitsToFill = min(nBits, iByteDest ? 8 : 8 - nDestPos);// 目标区当前字节要填充的起始位iBitDest = iByteDest ? 0 : nDestPos;// 计算可以一次从源数据区中复制的位数nBitsCanFill = min(nBitsToFill, 8 - iBitSrc);// 字节内复制CopyBitsInAByte(memDest + iByteDest, iBitDest,memSrc + iByteSrc, iBitSrc, nBitsCanFill);// 如果还没有复制完nBitsToFill 个if (nBitsToFill > nBitsCanFill){iByteSrc++; iBitSrc = 0; iBitDest += nBitsCanFill;CopyBitsInAByte(memDest + iByteDest, iBitDest,memSrc + iByteSrc, iBitSrc,nBitsToFill - nBitsCanFill);iBitSrc += nBitsToFill - nBitsCanFill;}else{iBitSrc += nBitsCanFill;if (iBitSrc >= 8){iByteSrc++; iBitSrc = 0;}}nBits -= nBitsToFill; // 已经填充了nBitsToFill位iByteDest++;}}// CopyBits//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// CopyBitsInAByte : 在一个字节范围内复制位流// 参数含义同CopyBits 的参数// 说明:// 此函数由CopyBits 调用,不做错误检查,即// 假定要复制的位都在一个字节范围内void CCompress::CopyBitsInAByte(BYTE* memDest, int nDestPos, BYTE* memSrc, int nSrcPos, int nBits){BYTE b1, b2;b1 <<= nSrcPos; b1 >>= 8 - nBits; // 将不用复制的位清b1 <<= 8 - nBits - nDestPos; // 将源和目的字节对齐*memDest |= b1; // 复制值为的位b2 = 0xff; b2 <<= 8 - nDestPos; // 将不用复制的位置b1 |= b2;b2 = 0xff; b2 >>= nDestPos + nBits;b1 |= b2;*memDest &= b1; // 复制值为的位}// CopyBitsInAByte///////////////////////////////////////////////////////////------------------------------------------------------------------CCompressLZ77::CCompressLZ77(){SortHeap = new struct STIDXNODE[_MAX_WINDOW_SIZE]; }CCompressLZ77::~CCompressLZ77(){delete[] SortHeap;}// 初始化索引表,释放上次压缩用的空间void CCompressLZ77::_InitSortTable(){memset(SortTable, 0, sizeof(WORD) * 65536);nWndSize = 0;HeapPos = 1;}// 向索引中添加一个字节串void CCompressLZ77::_InsertIndexItem(int off){WORD q;BYTE ch1, ch2;ch1 = pWnd[off]; ch2 = pWnd[off + 1];if (ch1 != ch2){// 新建节点HeapPos++;SortHeap[q].off = off;SortHeap[q].next = SortTable[ch1 * 256 + ch2];SortTable[ch1 * 256 + ch2] = q;}else{// 对重复字节串// 因为没有虚拟偏移也没有删除操作,只要比较第一个节点// 是否和off 相连接即可q = SortTable[ch1 * 256 + ch2];if (q != 0 && off == SortHeap[q].off2 + 1){// 节点合并SortHeap[q].off2 = off;}else{// 新建节点q = HeapPos;HeapPos++;SortHeap[q].off = off;SortHeap[q].off2 = off;SortHeap[q].next = SortTable[ch1 * 256 + ch2];SortTable[ch1 * 256 + ch2] = q;}}}//////////////////////////////////////////// 将窗口向右滑动n个字节void CCompressLZ77::_ScrollWindow(int n){for (int i = 0; i < n; i++){nWndSize++;if (nWndSize > 1)_InsertIndexItem(nWndSize - 2);}}///////////////////////////////////////////////////////////// 得到已经匹配了个字节的窗口位置offset// 共能匹配多少个字节int CCompressLZ77::_GetSameLen(BYTE* src, int srclen, int nSeekStart, int offset) {int i = 2; // 已经匹配了个字节int maxsame = min(srclen - nSeekStart, nWndSize - offset);while (i < maxsame&& src[nSeekStart + i] == pWnd[offset + i])i++;_ASSERT(nSeekStart + i <= srclen && offset + i <= nWndSize);return i;}///////////////////////////////////////////////////////////// 在滑动窗口中查找术语// nSeekStart - 从何处开始匹配// offset, len - 用于接收结果,表示在滑动窗口内的偏移和长度// 返回值- 是否查到长度为或以上的匹配字节串BOOL CCompressLZ77::_SeekPhase(BYTE* src, int srclen, int nSeekStart, int* offset, int* len){int j, m, n;if (nSeekStart < srclen - 1){BYTE ch1, ch2;ch1 = src[nSeekStart]; ch2 = src[nSeekStart + 1];WORD p;p = SortTable[ch1 * 256 + ch2];if (p != 0){m = 2; n = SortHeap[p].off;while (p != 0){j = _GetSameLen(src, srclen,nSeekStart, SortHeap[p].off);if ( j > m ){m = j;n = SortHeap[p].off;}p = SortHeap[p].next;}(*offset) = n;(*len) = m;return TRUE;}}return FALSE;}////////////////////////////////////////// 输出压缩码// code - 要输出的数// bits - 要输出的位数(对isGamma=TRUE时无效)// isGamma - 是否输出为γ编码void CCompressLZ77::_OutCode(BYTE* dest, DWORD code, int bits, BOOL isGamma){if ( isGamma ){BYTE* pb;DWORD out;// 计算输出位数int GammaCode = (int)code - 1;int q = LowerLog2(GammaCode);if (q > 0){out = 0xffff;pb = (BYTE*)&out;// 输出q个CopyBits(dest + CurByte, CurBit,pb, 0, q);MovePos(&CurByte, &CurBit, q);}// 输出一个out = 0;pb = (BYTE*)&out;CopyBits(dest + CurByte, CurBit, pb + 3, 7, 1);MovePos(&CurByte, &CurBit, 1);if (q > 0){// 输出余数, q位int sh = 1;sh <<= q;out = GammaCode - sh;pb = (BYTE*)&out;InvertDWord(&out);CopyBits(dest + CurByte, CurBit,pb + (32 - q) / 8, (32 - q) % 8, q);MovePos(&CurByte, &CurBit, q);}}else{DWORD dw = (DWORD)code;BYTE* pb = (BYTE*)&dw;InvertDWord(&dw);CopyBits(dest + CurByte, CurBit,pb + (32 - bits) / 8, (32 - bits) % 8, bits);MovePos(&CurByte, &CurBit, bits);}}/////////////////////////////////////////////// 压缩一段字节流// src - 源数据区// srclen - 源数据区字节长度// dest - 压缩数据区,调用前分配srclen+5字节内存// 返回值> 0 压缩数据长度// 返回值= 0 数据无法压缩// 返回值< 0 压缩中异常错误int CCompressLZ77::Compress(BYTE* src, int srclen, BYTE* dest) {int i;CurByte = 0; CurBit = 0;int off, len;if (srclen > 65536)return -1;pWnd = src;_InitSortTable();for (i = 0; i < srclen; i++){if (CurByte >= srclen)return 0;if (_SeekPhase(src, srclen, i, &off, &len)){// 输出匹配术语flag(1bit) + len(γ编码) + offset(最大bit)_OutCode(dest, 1, 1, FALSE);_OutCode(dest, len, 0, TRUE);// 在窗口不满k大小时,不需要位存储偏移_OutCode(dest, off, UpperLog2(nWndSize), FALSE);_ScrollWindow(len);i += len - 1;}else{// 输出单个非匹配字符0(1bit) + char(8bit)_OutCode(dest, 0, 1, FALSE);_OutCode(dest, (DWORD)(src[i]), 8, FALSE);_ScrollWindow(1);}}int destlen = CurByte + ((CurBit) ? 1 : 0);if (destlen >= srclen)return 0;return destlen;}/////////////////////////////////////////////// 解压缩一段字节流// src - 接收原始数据的内存区// srclen - 源数据区字节长度// dest - 压缩数据区// 返回值- 成功与否BOOL CCompressLZ77::Decompress(BYTE* src, int srclen, BYTE* dest) {int i;CurByte = 0; CurBit = 0;pWnd = src; // 初始化窗口nWndSize = 0;if (srclen > 65536)return FALSE;for (i = 0; i < srclen; i++){BYTE b = GetBit(dest[CurByte], CurBit);MovePos(&CurByte, &CurBit, 1);if (b == 0) // 单个字符{CopyBits(src + i, 0, dest + CurByte, CurBit, 8);MovePos(&CurByte, &CurBit, 8);nWndSize++;}else// 窗口内的术语{int q = -1;while (b != 0){q++;b = GetBit(dest[CurByte], CurBit);MovePos(&CurByte, &CurBit, 1);}int len, off;DWORD dw = 0;BYTE* pb;if (q > 0){pb = (BYTE*)&dw;CopyBits(pb + (32 - q) / 8, (32 - q) % 8, dest + CurByte, CurBit, q);MovePos(&CurByte, &CurBit, q);InvertDWord(&dw);len = 1;len <<= q;len += dw;len += 1;}elselen = 2;// 在窗口不满k大小时,不需要位存储偏移dw = 0;pb = (BYTE*)&dw;int bits = UpperLog2(nWndSize);CopyBits(pb + (32 - bits) / 8, (32 - bits) % 8, dest + CurByte, CurBit, bits);MovePos(&CurByte, &CurBit, bits);InvertDWord(&dw);off = (int)dw;// 输出术语for (int j = 0; j < len; j++){_ASSERT(i + j < srclen);_ASSERT(off + j < _MAX_WINDOW_SIZE);src[i + j] = pWnd[off + j];}nWndSize += len;i += len - 1;}// 滑动窗口if (nWndSize > _MAX_WINDOW_SIZE){pWnd += nWndSize - _MAX_WINDOW_SIZE;nWndSize = _MAX_WINDOW_SIZE;}}return TRUE;}。
LZ77算法在文本压缩中的应用

LZ77算法在文本压缩中的应用LZ77(Lempel-Ziv 77)算法是一种经典的文本压缩算法,于1977年由Jacob Ziv和Abraham Lempel提出。
LZ77算法基于一种称为“滑动窗口”的模式匹配思想。
它通过在滑动窗口内查找重复的字串,并使用指针(offset)和长度(length)来表示这些重复的字串。
使用这些指针和长度信息,可以将原始文本用更短的编码来表示,从而达到压缩数据大小的目的。
在阶段,LZ77算法从输入文本的开头开始,逐个字符进行。
它通过维护一个滑动窗口来最长的匹配字串。
滑动窗口首先是一个固定大小的缓冲区,起始位置为输入文本的开头,滑动窗口的大小可以根据具体的实现进行调整。
然后,LZ77算法逐个字符将输入文本推进滑动窗口,并在滑动窗口内与当前字符相匹配的最长字串。
这一过程可以使用各种字符串匹配算法来实现,常见的有暴力和Knuth-Morris-Pratt算法等。
一旦找到匹配的字串,LZ77算法记录指针和长度信息,并将其添加到输出流中。
指针(offset)表示匹配字串在滑动窗口中的位置,长度(length)表示匹配字串的长度。
然后,LZ77算法将滑动窗口推进到匹配字串的末尾,并继续进行。
如果没有找到匹配的字串,LZ77算法将当前字符作为一个独立的字节(literal)添加到输出流中,并将滑动窗口推进一个字符。
在编码阶段,LZ77算法将阶段产生的指针、长度和字节组合成一个编码对(<offset,length>, byte)的形式,并将其输出。
输出的编码对可以按照具体的格式进行存储,常见的有二进制格式和可打印的ASCII文本格式。
对于非压缩的字节,LZ77算法将其作为literal直接添加到输出流中。
最终,LZ77算法输出的数据流就是压缩后的文本。
LZ77算法的应用非常广泛,特别是在网络传输和存储领域。
由于网络带宽和存储容量的限制,需要对数据进行压缩以减少传输和存储成本。
lz77编码例题详解

lz77编码例题详解LZ77编码是一种无损数据压缩算法,它通过利用重复出现的数据来减少存储空间。
这种编码算法广泛应用于网络传输、数据存储和多媒体压缩等领域。
本文将详细解释LZ77编码的原理,并通过一个具体的例题加以说明。
LZ77编码的原理很简单。
算法从输入串的开头开始,依次扫描每个字符,并通过一个滑动窗口来进行匹配。
滑动窗口是一个固定大小的缓冲区,用于存储已经遍历过的字符。
当匹配到重复的字符时,算法将记录下重复字符之前的距离和重复字符个数,以此作为压缩数据的表示。
这样,在压缩数据中,只需要保存重复字符之前的距离和重复字符的个数,而不需要重复存储相同的字符。
假设输入序列为:ABABABA,滑动窗口大小为4。
算法的工作流程如下:1. 初始化滑动窗口和输出缓冲区。
初始状态下,滑动窗口为空,而输出缓冲区为一个空串。
2. 从输入串的开头开始扫描。
在此例中,我们首先扫描到字符"A"。
因为滑动窗口为空,所以直接将字符"A"添加到滑动窗口,并将其输出到缓冲区,即输出"A"。
3. 继续扫描下一个字符"B"。
此时滑动窗口为"A",并且滑动窗口中的字符与下一个字符"B"不匹配。
因此,将字符"B"添加到滑动窗口,并将其输出到缓冲区,即输出"B"。
4. 继续扫描下一个字符"A"。
此时滑动窗口为"AB",并且滑动窗口中的字符与下一个字符"A"匹配。
算法会记录下重复字符"A"之前的距离和重复字符的个数。
在这个例子中,距离为1,重复字符个数为1。
因此,将输出"<1,1>",表示重复字符之前的距离为1,重复字符个数为1。
5. 继续扫描下一个字符"B"。
压缩率高的压缩算法

压缩率高的压缩算法随着信息技术的不断发展,数据的存储和传输需求也越来越大。
为了更高效地利用存储空间和提高网络传输速度,压缩算法应运而生。
压缩算法是通过对数据进行编码和解码,以减少数据的存储空间和传输带宽的占用。
在众多压缩算法中,有一些算法以其高压缩率而著名。
一、LZ77压缩算法LZ77是一种基于字典的压缩算法,它通过利用重复出现的字符串来减少数据的存储空间。
该算法在编码过程中,将字符串分成固定大小的窗口,并在窗口内查找匹配的字符串。
编码时,将匹配的字符串用指针指向之前出现的位置,并记录匹配字符串之后的字符。
解码时,根据指针和记录的字符,可以还原出原始字符串。
LZ77算法在文本和图像等数据中具有较好的压缩效果,能够显著减少存储空间的占用。
二、哈夫曼编码哈夫曼编码是一种变长编码算法,它通过对频率较高的字符使用较短的编码,对频率较低的字符使用较长的编码,从而达到高压缩率的效果。
该算法首先统计字符出现的频率,然后根据频率构建哈夫曼树。
树的叶子节点表示字符,路径上的编码表示字符的编码。
编码时,将字符替换为对应的编码,解码时,根据编码树还原原始字符。
哈夫曼编码在文本和图像等数据中具有较高的压缩率,能够有效减少存储空间的占用。
三、算术编码算术编码是一种连续编码算法,它通过对数据中的每个符号进行编码,从而实现高压缩率的效果。
该算法将数据的范围映射到一个连续的区间,编码时,根据符号在区间中的位置来确定编码。
解码时,根据编码和区间映射关系还原原始数据。
算术编码在文本和图像等数据中具有较高的压缩率,能够极大地减少存储空间的占用。
四、LZW压缩算法LZW是一种基于字典的压缩算法,它通过建立字典来减少数据的存储空间。
该算法在编码过程中,将输入的字符串逐个字符地添加到字典中,并记录对应的编码。
当输入的字符串在字典中已经存在时,将其对应的编码输出,并将其与下一个字符组合成新的字符串添加到字典中。
解码时,根据编码和字典还原原始字符串。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
LZ77压缩算法实验报告一、实验内容使用C++编程实现LZ77压缩算法的实现。
二、实验目的用LZ77实现文件的压缩。
三、实验环境1、软件环境:Visual C++ 6.02、编程语言:C++四、实验原理LZ77 算法在某种意义上又可以称为“滑动窗口压缩”,这是由于该算法将一个虚拟的,可以跟随压缩进程滑动的窗口作为术语字典,要压缩的字符串如果在该窗口中出现,则输出其出现位置和长度。
使用固定大小窗口进行术语匹配,而不是在所有已经编码的信息中匹配,是因为匹配算法的时间消耗往往很多,必须限制字典的大小才能保证算法的效率;随着压缩的进程滑动字典窗口,使其中总包含最近编码过的信息,是因为对大多数信息而言,要编码的字符串往往在最近的上下文中更容易找到匹配串。
五、LZ77算法的基本流程1、从当前压缩位置开始,考察未编码的数据,并试图在滑动窗口中找出最长的匹配字符串,如果找到,则进行步骤2,否则进行步骤3。
2、输出三元符号组( off, len, c )。
其中off 为窗口中匹配字符串相对窗口边界的偏移,len 为可匹配的长度,c 为下一个字符。
然后将窗口向后滑动len + 1 个字符,继续步骤1。
3、输出三元符号组( 0, 0, c )。
其中c 为下一个字符。
然后将窗口向后滑动len + 1 个字符,继续步骤1。
六、源程序/*********************************************************************** Project description:* Lz77 compression/decompression algorithm.**********************************************************************/#include <windows.h>#include <conio.h>#include <stdio.h>#include <assert.h>#define OFFSET_CODING_LENGTH (10)#define MAX_WND_SIZE 1024//#define MAX_WND_SIZE (1<<OFFSET_CODING_LENGTH)#define OFFSET_MASK_CODE (MAX_WND_SIZE-1)const ULONG m=3;UCHAR __buffer1__[0x200000];UCHAR __buffer2__[0x200000];////////////////////////////////////////////////////////////////////////////////voidWrite1ToBitStream(PUCHAR pBuffer,ULONG ulBitOffset){ULONG ulByteBoundary;ULONG ulOffsetInByte;ulByteBoundary = ulBitOffset>>3 ;ulOffsetInByte = ulBitOffset&7;*(pBuffer+ulByteBoundary) |= (1<<ulOffsetInByte);}voidWrite0ToBitStream(PUCHAR pBuffer,ULONG ulBitOffset){ULONG ulByteBoundary;ULONG ulOffsetInByte;ulByteBoundary = ulBitOffset>>3 ;ulOffsetInByte = ulBitOffset&7;*(pBuffer+ulByteBoundary) &= (~(1<<ulOffsetInByte));}ULONGReadBitFromBitStream(PUCHAR pBuffer,ULONG ulBitOffset){ULONG ulByteBoundary;ULONG ulOffsetInByte;ulByteBoundary = ulBitOffset>>3 ;ulOffsetInByte = ulBitOffset&7;return ((*(PULONG)(pBuffer+ulByteBoundary))>>ulOffsetInByte)&1 ; }ULONG WINAPIWriteGolombCode(ULONG x,PUCHAR pBuffer,ULONG ulBitOffset){ULONG q, r;int i;q = (x-1)>>m;r = x-(q<<m)-1;for(i=0; (ULONG)i<q; i++, ulBitOffset++){Write1ToBitStream(pBuffer, ulBitOffset); }Write0ToBitStream(pBuffer, ulBitOffset);ulBitOffset++;for(i=0; i<m; i++, ulBitOffset++){if( (r>>i)&1 ){Write1ToBitStream(pBuffer, ulBitOffset);}else{Write0ToBitStream(pBuffer, ulBitOffset);}}return m+q+1;}ULONGReadGolombCode(PULONG pulCodingLength,PUCHAR pBuffer,ULONG ulBitOffset){ULONG q, r;ULONG bit;int i;for(q=0; ;q++){bit = (ULONG)ReadBitFromBitStream(pBuffer, ulBitOffset);ulBitOffset++;if( !bit ){break;}}for(i=0, r=0; (ULONG)i<m; i++, ulBitOffset++){bit = (ULONG)ReadBitFromBitStream(pBuffer, ulBitOffset);bit <<= i;r |= bit;}*pulCodingLength = m + q + 1;return r+(q<<m)+1;}ULONGCompareStrings(PUCHAR string1,PUCHAR string2,ULONG length){ULONG i;PUCHAR p1, p2;p1 = string1;p2 = string2;for(i=0; i<length; i++){if( *p1==*p2 ){p1++;p2++;}else{break;}}return p1-string1;}void WINAPIFindLongestSubstring(PUCHAR pSourceString,PUCHAR pString,ULONG ulSourceStringLength,PULONG pulSubstringOffset,PULONG pulSubstringLength){PUCHAR pSrc;ULONG offset, length;ULONG ulMaxLength;*pulSubstringOffset = offset = 0;*pulSubstringLength = 0;if( NULL==pSourceString || NULL==pString ){return;}ulMaxLength = ulSourceStringLength;pSrc = pSourceString;while( ulMaxLength>0 ){length = CompareStrings(pSrc, pString, ulMaxLength);if( length>*pulSubstringLength ){*pulSubstringLength = length;*pulSubstringOffset = offset;}pSrc++;offset++;ulMaxLength--;}}/*voidFindLongestSubstring(PUCHAR pSourceString,PUCHAR pString,ULONG ulSourceStringLength,PULONG pulSubstringOffset,PULONG pulSubstringLength){PUCHAR pCurrentOffset;PUCHAR p1, p2;ULONG offset, length;pCurrentOffset = pSourceString;*pulSubstringOffset = offset = 0;*pulSubstringLength = length = 0;while( pCurrentOffset<pSourceString+ulSourceStringLength ){p1 = pCurrentOffset;p2 = pString;if( *p1==*p2 ){while( p1<pSourceString+ulSourceStringLength && *p1==*p2 ){p1++;p2++;}length = p1 - pCurrentOffset;}else{length = 0;}if( length>*pulSubstringLength ){*pulSubstringLength = length;*pulSubstringOffset = (ULONG)pCurrentOffset - (ULONG)pSourceString;}pCurrentOffset++;}}*/voidWriteBits(PUCHAR pDataBuffer,ULONG ulOffsetToWrite,ULONG ulBits,ULONG ulBitLength){ULONG ulDwordsOffset;ULONG ulBitsOffset, ulBitsRemained;ulDwordsOffset = ulOffsetToWrite>>5;ulBitsOffset = ulOffsetToWrite&31;ulBitsRemained = 32 - ulBitsOffset;if( 0==ulBitsOffset ){*((PULONG)pDataBuffer+ulDwordsOffset) = ulBits;}else if( ulBitsRemained>=ulBitLength ){*((PULONG)pDataBuffer+ulDwordsOffset) |= (ulBits<<ulBitsOffset);}else{*((PULONG)pDataBuffer+ulDwordsOffset) |= (ulBits<<ulBitsOffset);*((PULONG)pDataBuffer+ulDwordsOffset+1) = ulBits>>ulBitsRemained; }}voidReadBits(PUCHAR pDataBuffer,ULONG ulOffsetToRead,PULONG pulBits){ULONG ulDwordsOffset;ULONG ulBitsOffset, ulBitsLength;ulDwordsOffset = ulOffsetToRead>>5;ulBitsOffset = ulOffsetToRead&31;ulBitsLength = 32 - ulBitsOffset;*pulBits = *((PULONG)pDataBuffer+ulDwordsOffset);if( 0!=ulBitsOffset ){(*pulBits) >>= ulBitsOffset;(*pulBits) |= (*((PULONG)pDataBuffer+ulDwordsOffset+1))<<ulBitsLength; }}voidlz77compress(PUCHAR pDataBuffer,ULONG ulDataLength,PUCHAR pOutputBuffer,PULONG pulNumberOfBits){LONG iSlideWindowPtr;ULONG ulBytesCoded;ULONG ulMaxlength;PUCHAR pSlideWindowPtr;PUCHAR pUnprocessedDataPtr;ULONG offset;ULONG length;ULONG ulCodingLength;ULONG ulBitOffset;UCHAR cc;int i;iSlideWindowPtr = -MAX_WND_SIZE;pSlideWindowPtr = NULL;ulBitOffset = 0;ulBytesCoded = 0;while( ulBytesCoded<ulDataLength ){if( iSlideWindowPtr>=0 ){pSlideWindowPtr = pDataBuffer+iSlideWindowPtr;ulMaxlength = MAX_WND_SIZE;}else if( iSlideWindowPtr>=-MAX_WND_SIZE ){pSlideWindowPtr = pDataBuffer;ulMaxlength = MAX_WND_SIZE + iSlideWindowPtr;}else{pSlideWindowPtr = NULL;ulMaxlength = 0;}pUnprocessedDataPtr = pDataBuffer + ulBytesCoded;if( ulMaxlength>ulDataLength-ulBytesCoded ){ulMaxlength = ulDataLength-ulBytesCoded;}FindLongestSubstring(pSlideWindowPtr,pUnprocessedDataPtr,ulMaxlength,&offset,&length);assert( length<=MAX_WND_SIZE );assert( offset<MAX_WND_SIZE );if(length>1){Write1ToBitStream(pOutputBuffer, ulBitOffset);ulBitOffset++;for(i=0; i<OFFSET_CODING_LENGTH; i++, ulBitOffset++){if( (offset>>i)&1 ){Write1ToBitStream(pOutputBuffer, ulBitOffset);}else{Write0ToBitStream(pOutputBuffer, ulBitOffset);}}ulCodingLength = WriteGolombCode(length, pOutputBuffer, ulBitOffset);ulBitOffset += ulCodingLength;iSlideWindowPtr += length;ulBytesCoded += length;}else{Write0ToBitStream(pOutputBuffer, ulBitOffset);ulBitOffset++;cc = (*pUnprocessedDataPtr);for(i=0; i<8; i++, ulBitOffset++){if( (cc>>i)&1 ){Write1ToBitStream(pOutputBuffer, ulBitOffset);}else{Write0ToBitStream(pOutputBuffer, ulBitOffset);}}iSlideWindowPtr++;ulBytesCoded++;}}if( ulBytesCoded!=ulDataLength ){assert(ulBytesCoded==ulDataLength);}*pulNumberOfBits = ulBitOffset;}void lz77decompress(PUCHAR pDataBuffer,ULONG ulNumberOfBits,PUCHAR pOutputBuffer,PULONG pulNumberOfBytes){LONG iSlideWindowPtr;PUCHAR pSlideWindowPtr;ULONG length, offset;ULONG bit;UCHAR cc;int i;ULONG ulBytesDecoded;ULONG ulBitOffset;ULONG ulCodingLength;PUCHAR pWrite;iSlideWindowPtr = -MAX_WND_SIZE;pWrite = (PUCHAR)pOutputBuffer;ulBitOffset = 0;ulBytesDecoded = 0;while( ulBitOffset<ulNumberOfBits ){bit = ReadBitFromBitStream(pDataBuffer, ulBitOffset);ulBitOffset++;if( bit ){if( iSlideWindowPtr>=0 ){pSlideWindowPtr = pOutputBuffer + iSlideWindowPtr;}else if( iSlideWindowPtr>=-MAX_WND_SIZE ){pSlideWindowPtr = pOutputBuffer;}else{pSlideWindowPtr = NULL;}for(i=0, offset=0; i<OFFSET_CODING_LENGTH; i++, ulBitOffset++){bit = ReadBitFromBitStream(pDataBuffer, ulBitOffset);offset |= (bit<<i);}length= ReadGolombCode(&ulCodingLength, pDataBuffer, ulBitOffset);assert(offset<MAX_WND_SIZE);if( length>MAX_WND_SIZE ){assert(length<=MAX_WND_SIZE);}ulBitOffset += ulCodingLength;RtlMoveMemory(pWrite, pSlideWindowPtr+offset, length);pWrite+=length;iSlideWindowPtr+=length;ulBytesDecoded+=length;}else{for(i=0, cc=0; i<8 ; i++, ulBitOffset++){bit = ReadBitFromBitStream(pDataBuffer, ulBitOffset);cc |= ((UCHAR)bit<<i);}*pWrite++ = cc;iSlideWindowPtr++;ulBytesDecoded++;}}*pulNumberOfBytes = ulBytesDecoded;}extern "C"void WINAPILZ77Compress(PUCHAR __pDataBuffer,ULONG __ulDataLength,PUCHAR __pOutputBuffer,PULONG __pulNumberOfBits);extern "C"void WINAPILZ77Decompress(PUCHAR __pDataBuffer,ULONG __ulNumberOfBits,PUCHAR __pOutputBuffer,PULONG __pulNumberOfBytes);intmain(int argc,char *argv[]){FILE *fp=NULL;FILE *fp1;ULONG fsize;ULONG ulNumberOfBits;ULONG ulFileCompressedSize;ULONG ulFileDecompressedSize;SYSTEMTIME t1, t2;if( 3!=argc ){printf("Usage: lz77 [/c | /d] filename\n");return -1;}// char s1[]="abcdabcdefgabcdefaffasda";// ULONG a, b;// FindLongestSubstring((PUCHAR)s1, (PUCHAR)s1+11, 11,&a, &b ); // return 0;fp = fopen(argv[2], "rb");if( !fp ){return -1;}fseek(fp, 0, SEEK_END);fsize = ftell(fp);fseek(fp, 0, SEEK_SET);fread(__buffer1__, 1, fsize, fp);GetSystemTime(&t1);lz77compress(__buffer1__, fsize, __buffer2__, &ulNumberOfBits);//LZ77Compress(__buffer1__, fsize, __buffer2__, &ulNumberOfBits); GetSystemTime(&t2);ulFileCompressedSize = ((ulNumberOfBits+7)>>3);fp1=fopen("peinfo.c_", "wb+");if( !fp1 ){goto l1;}fwrite(__buffer2__, 1, ulFileCompressedSize, fp1);fclose(fp1);RtlZeroMemory(__buffer1__, sizeof(__buffer1__));lz77decompress(__buffer2__, ulNumberOfBits, __buffer1__, &ulFileDecompressedSize);//LZ77Decompress(__buffer2__, ulNumberOfBits, __buffer1__, &ulFileDecompressedSize); fp1=fopen("peinfo.d_", "wb+");if( !fp1 ){goto l1;}fwrite(__buffer1__, 1, ulFileDecompressedSize, fp1);fclose(fp1);l1:if( fp ){fclose(fp);}ULONG milliS;milliS = ((t2.wHour - t1.wHour)*3600 + (t2.wMinute-t1.wMinute)*60 + (t2.wSecond-t1.wSecond)) * 1000 + (t2.wMilliseconds-t1.wMilliseconds);printf("Totally %ld milliseconds elapsed!\n\n", milliS);printf("Press any key to exit!\n");getch();return 0; }七、实验结果。