[原创]用哈希表优化的lz77压缩算法的实现

2024-02-24 02:08

本文主要是介绍[原创]用哈希表优化的lz77压缩算法的实现,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

 

最近终于有空研究研究E*F的K*KYU2。
和预料到的一样仍然是广泛使用LZ77,而且是毫不改变地使用LZ77……但是,时代进步了,图片文件都是真彩色的了,大小变大了3倍,仍然使用LZ77的代价就是速度……大家都知道LZ77的特点就是解压超快,压缩巨慢(不然就不会有LZW这种不伦不类的算法出来了……)
在png的相关网站上查找了一下优化方案,自己写了一下优化代码,虽然目前速度仍然不能很让人满意(在双核的机器上压缩一个160多兆的文件用了60多秒),但是勉强可以用于实际应用了。贴出来和大家分享。如果要进一步优化,估计要玩一些trick,或是借助于指令级别的。
以下讨论是基于4096字节定长窗口的字典的LZ77,字节组织是每bit表示查表或是原数据;查表是2字节,前16位表示索引,后16位表示长度,因此最长的序列只能有15字节。优化的思路是哈希表。
由环境可以看出,低于3个字节的码序列是不需要查表保存的,因此码的最短长度是3个字节。使用一个哈希算法将之转化成1个字节的哈希码。这种哈希码共有256个。当在查表前,首先要计算出当前字节及后面两个字节组成的序列的哈希码,然后在哈希码表中查得第一条匹配记录。当然,即使哈希码匹配,3字节并不一定完全一样,这之后还是需要按字节比较。但这可以提前淘汰大部分的数据。匹配后,再查下一条记录。
优化的负担是额外增加了一个哈希码头指针表和一个链表。每一个字节在字典中的更新都会造成它本身及前面两个字节处共3个字节的哈希码变化,即表项删除和增加。为了使这种删除和增加更有效率,做成了双向链表的形式(实际测试下来比单向节省约一半时间)。当然这里的链表是以数组形式实现的,不需要动态分配空间,否则所带来的负担将是不可承受的。字典定义如下:

typedef  struct  _tagLz77Dict  {
    
int     hash_start[256];
    
int     hash_next[4096];
    
int     hash_prev[4096];
    
char    dict[4096];
}
 lz77_dict,  * p_lz77_dict;

其中,hash_start是256个哈希码的首码索引。hash_next是每个哈希码的下一个编码,hash_prev是每个哈希码的前一个编码。均以-1表示无效。
字典初始化函数如下:

void  init_dict(p_lz77_dict pdic)
{
    
int i;
    memset(pdic
->dict, 04096);
    
for (i = 0; i < 256++i) pdic->hash_start[i] = -1;
    pdic
->hash_start[HASH(000)] = 4096-16;
    
for (i = 0; i < 4096++i) {
        
if (i < 4096-16{
            pdic
->hash_next[i] = -1;
            pdic
->hash_prev[i] = -1;
        }
 else {
            pdic
->hash_next[i] = (i+1);
            pdic
->hash_prev[i] = (i-1);
        }

    }

    pdic
->hash_prev[0= -1;
    pdic
->hash_next[4095= -1;
}

初始值仅后面16个码可用。
删除和增加哈希码函数:

void  remove_dict_pos(p_lz77_dict pdic,  int  pos)
{
    
char a, b, c;
    unsigned 
char hash;

这篇关于[原创]用哈希表优化的lz77压缩算法的实现的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/740614

相关文章

Java实现检查多个时间段是否有重合

《Java实现检查多个时间段是否有重合》这篇文章主要为大家详细介绍了如何使用Java实现检查多个时间段是否有重合,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录流程概述步骤详解China编程步骤1:定义时间段类步骤2:添加时间段步骤3:检查时间段是否有重合步骤4:输出结果示例代码结语作

使用C++实现链表元素的反转

《使用C++实现链表元素的反转》反转链表是链表操作中一个经典的问题,也是面试中常见的考题,本文将从思路到实现一步步地讲解如何实现链表的反转,帮助初学者理解这一操作,我们将使用C++代码演示具体实现,同... 目录问题定义思路分析代码实现带头节点的链表代码讲解其他实现方式时间和空间复杂度分析总结问题定义给定

Java覆盖第三方jar包中的某一个类的实现方法

《Java覆盖第三方jar包中的某一个类的实现方法》在我们日常的开发中,经常需要使用第三方的jar包,有时候我们会发现第三方的jar包中的某一个类有问题,或者我们需要定制化修改其中的逻辑,那么应该如何... 目录一、需求描述二、示例描述三、操作步骤四、验证结果五、实现原理一、需求描述需求描述如下:需要在

如何使用Java实现请求deepseek

《如何使用Java实现请求deepseek》这篇文章主要为大家详细介绍了如何使用Java实现请求deepseek功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1.deepseek的api创建2.Java实现请求deepseek2.1 pom文件2.2 json转化文件2.2

python使用fastapi实现多语言国际化的操作指南

《python使用fastapi实现多语言国际化的操作指南》本文介绍了使用Python和FastAPI实现多语言国际化的操作指南,包括多语言架构技术栈、翻译管理、前端本地化、语言切换机制以及常见陷阱和... 目录多语言国际化实现指南项目多语言架构技术栈目录结构翻译工作流1. 翻译数据存储2. 翻译生成脚本

如何通过Python实现一个消息队列

《如何通过Python实现一个消息队列》这篇文章主要为大家详细介绍了如何通过Python实现一个简单的消息队列,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录如何通过 python 实现消息队列如何把 http 请求放在队列中执行1. 使用 queue.Queue 和 reque

Python如何实现PDF隐私信息检测

《Python如何实现PDF隐私信息检测》随着越来越多的个人信息以电子形式存储和传输,确保这些信息的安全至关重要,本文将介绍如何使用Python检测PDF文件中的隐私信息,需要的可以参考下... 目录项目背景技术栈代码解析功能说明运行结php果在当今,数据隐私保护变得尤为重要。随着越来越多的个人信息以电子形

使用 sql-research-assistant进行 SQL 数据库研究的实战指南(代码实现演示)

《使用sql-research-assistant进行SQL数据库研究的实战指南(代码实现演示)》本文介绍了sql-research-assistant工具,该工具基于LangChain框架,集... 目录技术背景介绍核心原理解析代码实现演示安装和配置项目集成LangSmith 配置(可选)启动服务应用场景

使用Python快速实现链接转word文档

《使用Python快速实现链接转word文档》这篇文章主要为大家详细介绍了如何使用Python快速实现链接转word文档功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 演示代码展示from newspaper import Articlefrom docx import

前端原生js实现拖拽排课效果实例

《前端原生js实现拖拽排课效果实例》:本文主要介绍如何实现一个简单的课程表拖拽功能,通过HTML、CSS和JavaScript的配合,我们实现了课程项的拖拽、放置和显示功能,文中通过实例代码介绍的... 目录1. 效果展示2. 效果分析2.1 关键点2.2 实现方法3. 代码实现3.1 html部分3.2