【压缩算法】LZ77算法

一、算法介绍

LZ77算法是采用自适应的字典模型,也就i是将已经编码的信息作为字典,如果要编码的字符曾经出现过,就输出该字符串的出现位置以及长度,否则输出新的字符串。

二、算法思想

它的核心思想是在前面已经出现过的数据中找重复出现的字符,根据局部性原理,入股一个字符串要重复,那么也实在附近重复,远的地方就不要找了,因此设置一个滑动窗口,每次都在这个窗口里面找重复出现的字符。

关于这个滑动窗口的大小,理论上是窗口越大,重复的可能性越高,压缩效率越高。但是窗口太大的话,查找的效率也会降低。
在LZ77算法中设置滑动窗口的大小为32k。

三、算法实现

  1. 经过LZ77算法后,一段字符串可以表示为“原文和距离+长度”的形式。我们可以在每一个字符后面都加一个bit位的标志位用于区分“原文”和“距离+长度”,这个bit位为0表示原文,为1表示“长度+距离”
  2. 由于滑动窗口只有32k,如果我们对距离采用定长编码的话,最多用两个字节就可以表示。
  3. 对于重复的长度我们也采用定长编码,并且规定最多一次匹配255个字符。这样的话用一个字节就可以表示
  4. 由于“距离+长度”我们使用3个字节表示,所以当重复的字节数大于等于3的时候,才不会导致我们越压越大。
    这里写图片描述

四、算法分析

在滑动窗口匹配数据的时候,我们可以将数据加载到内存中再进行匹配。但是只使用32K的窗口的话,每一次匹配的字符串我们都必须将前32k的内容重新加载一次,这样的话效率简直太低了。
为此,我们可以使用64k的缓存,将要匹配的位置的前32k和后32k内容都读到缓存中,这样的话,我们每处理32k的内容才读一次数据。
这里写图片描述

五、代码

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <cstdio>
#include <cassert>
#include <cstdlib>
#include <algorithm>
#include <vector>
using namespace std;

const size_t N = 2 * 32 * 1024;  //64k缓存
enum{ SlipBlock = 32 * 1024 };   //定义一个32K大小的滑块

typedef long long LongType;

class ZipCompress
{
private:
    vector<unsigned char> _windows; //滑块大小
    size_t _frist;
    size_t _last;
public:
    ZipCompress()
    {
        _windows.reserve(N); //开辟一个窗口,大小N
        _frist = 0;
        _last = 0;
    }

    string Compress(const string& filename)
    {
        return  _ZIP_FileCompress(filename);
    }

    string UnCompress(const string& filename)
    {
        return _ZIP_FileUnCompress(filename);
    }
private:
    string  _ZIP_FileCompress(const string& filename)
    {
        assert(filename.c_str());
        string FirstCompressFileName = filename;
        FirstCompressFileName += ".fzip";

        FILE* fInput = fopen(filename.c_str(), "rb+");
        assert(fInput);

        FILE* fOut = fopen(FirstCompressFileName.c_str(), "wb+");
        assert(fOut);

        FILE* pWindows = fopen(filename.c_str(), "rb+"); //定义指向滑动窗口起始位置
        assert(pWindows);

        int
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值