LZW的编码和解码

    不同于哈弗曼编码针对于每个元素编码,LZW主要针对字符串的编码优化,也就是把出现频率高的字符串压缩成一个字符表示,这也是大名鼎鼎的GIF采用的压缩格式。下面我将从三个角度谈谈我的一些理解,文章主要参考了这位大佬:LZW编解码详解_lzw编码-CSDN博客。

思想简述

    LZW主要针对字符串压缩。比如对于字符串ABAB,首先对于每个会出现的字符都有一个默认编码,也就是A-0,B-1,因为LZW的压缩要求解压时不需要压缩编码表,因此是要求不需要编码表重建的,所以第一个A和第二个B不能连在一起压缩,分别编码为0和1;然后因为AB出现过了,记录在字典中,即AB-2,所以后面的AB就直接编码为2,编码后的字符串为012。

    可以想象,如果直接把两个AB都变成2,那么压缩后是22,一上来就是一个2,那么无法重建字典了,因为这个2怎么来的无从得知。

如何压缩

    压缩的过程相比解压要简单,简单来说就是维护两个字符串,分别是未编码P和当前字符C,这里的P是当前最长的可编码字符串,C就是当前指向的字符,比如xyabcdef,假设此时P起点为的a,终点是d(加粗处),此时C指向的e,假设abcd+e在字典中出现了,那么P更新为P+C也就是abcde,相当于此时还可能继续往下找到更长的编进字典;如果abcd+e没有出现在字典中,那么最长的可编码字符串就是abcd,此时为这个字符串编码,并且在字典中增加一个新的编码对应abcde,同时更新P为e(更新为指针C指向的字符),继续找下面的最长可编码字符串。

    这个过程简单来说就是找最长可编码字符串,一直找到无法编码了,为字符串编码,把无法编码的加入字典

算法步骤如下:

  1. 初始状态,字典里只有所有的默认项,例如0->a,1->b,2->c。此时P和C都是空的。

  2. 读入新的字符C,与P合并形成字符串P+C。

  3. 在字典里查找P+C,如果:

    • P+C在字典里,P=P+C。

    • P+C不在字典里,将P的记号输出;在字典中为P+C建立一个记号映射;更新P=C。

  4. 返回步骤2重复,直至读完原字符串中所有字符。

    下面是对于ababcababac的编码过程,可以对照,编码后的结果是0132372

如何解码

    解码略复杂。可以想想编码的过程,编码的过程实际上就是找到P和C,然后把P编码,把P+C放入字符串,解码就反过来,将当前码值解码,并且把当前码值的解码(P)和下一个码值对应的解码的首字符(C)加入字典。

    具体实现还是维护P和C,只不过P代表当前编码对应字符串,C代表下一个位置的编码对应字符串的首字符

算法流程如下:

  1. 初始状态,字典里只有所有的默认项,例如0->a,1->b,2->c。此时pW和cW都是空的。

  2. 读入第一个的符号cW,解码输出。注意第一个cW肯定是能直接解码的,而且一定是单个字符。

  3. 赋值pW=cW。

  4. 读入下一个符号cW。

  5. 在字典里查找cW,如果: a. cW在字典里: (1) 解码cW,即输出 Str(cW)。 (2) 令P=Str(pW),C=Str(cW)的第一个字符。 (3) 在字典中为P+C添加新的记号映射。 b. cW不在字典里: (1) 令P=Str(pW),C=Str(pW)的第一个字符。 (2) 在字典中为P+C添加新的记号映射,这个新的记号一定就是cW。 (3) 输出P+C。

  6. 返回步骤3重复,直至读完所有记号。

下面是推导的过程,可以参考对照一下:

 

下面是具体的过程解析:

    在解码时,我们面对的实际上是一串数字,就像是0132372这样 ,我们一开始知道的是默认的编码规则,也是就是a-0,b-1,c-2...,假设对于编码后的字符串0132372,编码是把最长可编码字符串P+C编为新的字典元素,P实际就是这里的其中一个元素,比如0,而C就是P的后一个元素,也就是0后面的1串解码后的第一个字符(这个第一个很关键,后面的我都不管,我就要第一个,这是由编码决定的),解码过程就呼之欲出了,P指向一个元素,C是下一个元素,分两种情况讨论(建议先写一遍上面的过程,然后再看):

  1. 如果C对应的解码可以直接从字典中找到,比如P对应0,C对应1,此时0解码为a,1解码为b,P=a,C=b(1解码后的第一个字符),把P+C加入字典,也就是ab-2。

  2. 如果C对应的解码不能直接从字典中找到,就比如到了这里的37部分,p=3解码为ab,C=7,但是字典中还未出现7对应的元素,这时就要想想是什么导致了这种情况?

    先看7是怎么来的,在编码时,ca编码为6之后,P更新为a,然后找到P=ab发现ab字典中也有,所以保留,再往后此时C指向a,aba字典中没有,于是给aba编码为7,更新P为a。

    回到解码,此时37的P=3解码为ab,C对应7,7在字典中找不到,就说明编码7一定同时用到了3和7的首字符,看下图:

 

         不考虑前后的细节,用...代替,这里的P=3=ab,C+y对应的是7对应的解码字符串,目前还不知道 7的编码规则,无法解码。假如 7的编码没有用到P,那么两种情况:一种是7在P之前就编码好了,那么此时7应该在字典中,矛盾;一种是7的编码在C+y+...中编好,这与编码时寻找可编码字符串矛盾,因为还没放入字典就被用了,所以唯一可能性就是7的编码用到了前面的P,而由于7还未解码,因此对应的解码规则也还没被推导出来,而我们关心的放入字典的就是7的首字符,那么其实也就是这里P的首字符a,所以新的规则P+C(P的第一个)=aba-7加入字典,解码7。

    最后这段解析比较绕,我自己也绕来绕去感觉有点乱,有不足和错误可以直接指正。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/191270.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

抖音短视频优化的四个问题

短视频营销无疑是当下营销方式中最热的一种没有之一,但随着各家都把精力投向短视频营销,短视频平台的短视频内容急剧增加,而不做优化的短视频可能获得的展现机会很少,而营销效果大打折扣。小马识途营销顾问分析这就像互联网兴起的…

jionlp :一款超级强大的Python 神器!轻松提取地址中的省、市、县

在日常数据处理中,如果你需要从一个完整的地址中提取出省、市、县三级地名,或者乡镇、村、社区两级详细地名,你可以使用一个第三方库来实现快速解析。在使用之前,你需要先安装这个库。 pip install jionlp -i https://pypi.douba…

SQL Sever 基础知识 - 数据筛选

SQL Sever 基础知识 - 四、数据筛选 四、筛选数据第1节 DISTINCT - 去除重复值1.1 SELECT DISTINCT 子句简介1.2 SELECT DISTINCT 示例1.2.1 DISTINCT 一列示例1.2.2 DISTINCT 多列示例 1.2.3 DISTINCT 具有 null 值示例1.2.4 DISTINCT 与 GROUP BY 对比 第2节 WHERE - 过滤查询…

jvm基本概念,运行的原理,架构图

文章目录 JVM(1) 基本概念:(2)运行过程 今天来和大家聊聊jvm, JVM (1) 基本概念: JVM 是可运行Java代码的假想计算机,包括一套字节码指令集、一组寄存器、一个栈一个垃圾回收,堆 和 一个存储方法域。JVM 是运行在操作…

【智能家居】三、添加语音识别模块的串口读取功能点

语音识别模块SU-03T 串口通信线程控制代码 inputCommand.h(输入控制指令)voiceControl.c(语音控制模块指令)main.c(主函数)编译运行结果 语音识别模块SU-03T AI智能语音识别模块离线语音控制模块语音识别…

YOLOv8界面-目标检测+语义分割+追踪+姿态识别(姿态估计)+界面DeepSort/ByteTrack-PyQt-GUI

YOLOv8-DeepSort/ByteTrack-PyQt-GUI:全面解决方案,涵盖目标检测、跟踪和人体姿态估计 YOLOv8-DeepSort/ByteTrack-PyQt-GUI是一个多功能图形用户界面,旨在充分发挥YOLOv8在目标检测/跟踪和人体姿态估计/跟踪方面的能力,与图像、…

2023.11.30 关于 MyBatis 动态 SQL 的使用

目录 引言 if 标签 trim 标签 where 标签 set 标签 foreach 标签 引言 动态 sql 是 MyBatis 的强大特性之一允许你根据输入的参数动态地构建 sql 语句从而在运行时根据不同的条件生成不同的 sql 核心思想 基于提供的数据和条件,能够修改、增加、删除 sql…

二分查找思路实现

二分查找是一种很常见的查找算法,重要的是边界的处理和循环的起止条件 使用二分查找的话,首先接收的数组一定是有序的。确定边界。在头一次循环中,左边界也就是索引下标为0的位置,右边界是数组的长度-1.确定循环起止条件。当左边…

C语言面试之数组指针上篇

C语言数组是C语言中重要的数据结构之一,它用于存储一组相同类型的数据。数组在C语言中是以连续的内存空间来存储的,每个数组元素都是一个变量,占据一定的内存空间,数组元素之间是紧密相邻的。 一、数组的定义 在C语言中&#xff0…

vue常见优化手段

永远不要过早优化 why?过早优化的代价就是开发时间变长,开发成本增加,它会慢慢的让我们的代码变得不可阅读,难以维护;这些都是优化带来的代价。有句话是这样说的:命运馈赠的礼物,早已在暗中标好…

有点迷糊class和初始化参数的用法了

翻阅手册https://www.runoob.com/python3/python3-class.html Python从设计之初就已经是一门面向对象的语言,正因为如此,在Python中创建一个类和对象是很容易的。本章节我们将详细介绍Python的面向对象编程。 如果你以前没有接触过面向对象的编程语言&…

解决因系统重装,导致QT编译器无法使用的办法

1.报错 ERROR WHILE BUILDING/DEPLOYING PROJECT QTTEXT (KIT: DESKTOP QT 5.5.1 MINGW 32BIT) WHEN EXECUTING 解决方法: 出现Error while building/deploying project Qttext (kit: Desktop Qt 5.5.1 MinGW 32bit) When executing step "qmake"可能会…

力扣.特定深度节点链表(java BFS解法)

Problem: 面试题 04.03. 特定深度节点链表 文章目录 题目描述思路解题方法复杂度Code 题目描述 思路 根据题意需要取出二叉树每一层节点组成的链表并将其添加到一个数组中。我们将该要求分解成如下的操作: 1.利用BFS获取二叉树每一层的节点 2.利用链表的尾插法将二…

Android 13 - Media框架(15)- OpenMax(三)

上一节学习了 media.codec 服务中的部分内容,这一节我们将一起了解 OMX IL 层的 API 以及相关的结构体等内容。 1、相关路径 以下是 Media 相关的头文件路径: frameworks/native/headers/media_plugin/media/ cas 和 drm 是用于加密流解密使用&#xff…

Elasticsearch 如何处理 Aggs 顺序中的大写字母和小写字母?

Elasticsearch 排序允许你根据特定条件对搜索结果进行排序。 然而,在排序时处理区分大小写时,Elasticsearch 将大写和小写字母视为不同的字符,分别对它们进行排序。 这是因为 ASCII 表顺序是从大写 A 到小写 z。 默认情况下,Elas…

6大关键词:尝新/随心/低忠诚···,全面解读食品饮料行业发展趋势与消费者洞察|徐礼昭

内容:重构零售实验室&商派 《2023食品饮料行业零售数字化洞察报告》节选 作者:徐礼昭(商派市场负责人,重构零售实验室负责人) 如今品牌的影响力不再止于资本与业绩数字,更多是在产品核心价值以及消费…

Xilinx FPGA平台DDR3设计详解(二):DDR SDRAM组成与工作过程

本文主要介绍一下DDR SDRAM的基本组成以及工作过程,方便大家更好的理解和掌握DDR的控制与读写。 一、DDR SDRAM的基本组成 1、SDRAM的基本单元 SDRAM的基本单元是一个CMOS晶体管和一个电容组成的电路。 晶体管最上面的一端,称作栅极,通过…

005、简单页面-容器组件

之——布局 目录 之——布局 杂谈 正文 1.布局基础知识 2.Column 3.Row 4.实践 杂谈 布局容器组件。 一个丰富的页面需要很多组件组成,那么,我们如何才能让这些组件有条不紊地在页面上布局呢?这就需要借助容器组件来实现。 容器组件是…

C语言中的格式化输出符号:%d %c %p %x等

文章目录 概览%d%c%d和%c的区别%p%x %X输出浮点数参考 概览 C语言中的格式化输出符号有很多,以下是一些常见的: %d 或 %i:用于输出十进制整数。 %u:用于输出无符号十进制整数。 %f:用于输出浮点数。 %s:用…

Android 13 - Media框架(19)- ACodec(一)

这一节我们将会了解 ACodec 的状态转换机制,从 ACodec 的基类名称HierarchicalStateMachine来看,它用到的是分层状态机,了解这里的状态转换将会对我们学习 OpenMax 会有所帮助,也会对我们自己的代码书写有所帮助。 1、AHierarchic…