众所周知,在数据量较大,占用空间非常多的时候,我们就要想办法去压缩这些数据,于是就产生了各种各样的压缩算法,今天博主来介绍一种简单的压缩算法,并给出该算法的一种解决方案。
什么是RLE压缩算法
RLE(Run Length Encoding)压缩算法全称是行程长度压缩算法,是最早出现的、无损的压缩算法之一,那具体是什么样的呢,看看下面的例子吧。
现在给出一段字符串(不包含数字的数据),这是很小的数据:xaaaaaaabbbbbcdde
不难看出,这段字符串中有很多重复的内容,而我们要做的就是压缩它,但是有一定的要求:
● 单个字符(不重复的字符)不被压缩
● 压缩速度要快
● 无损压缩
我们要把它压缩成 x7a5bc2de 的样子,而将这段字符串压缩成数字+重复字符格式的算法就 RLE压缩算法,它在数据中有很多重复字符的时候非常有用,能拥有极高的压缩率。但这里有一点要注意的是,要压缩的数据里是不能包含数字字符的,否则压缩后再解压会出 BUG。因为解压程序会把数字识别为重复字符的个数,而不是重复字符本身,这也可能就是这个算法唯一的缺陷吧。
如何实现RLE压缩算法
第一种情况
(输入数据是有大量重复但不包含数字的数据)
博主的基本思路是检测相邻的两个字符是否相同来判断是否把数据中的某一部分内容压缩到一起
代码及相关解释如下:(压缩代码一)
string = input() #输入字符串
string = str(string)+' ' #这里的' '为input()里面必定没有的字符,方便后面程序的进行
count = 1 #设置初始计数器为1(至少有一个)
outlist = '' #设置一个列表用于储存结果
for i in range(len(string)-1): #遍历string里的所有元素(不包括最后一个' ')
if string[i] == string[i+1]: #判断前后两个是否相同
count +=1 #相同,计算器就加一
else: #如果不同
outlist +=str(count)+string[i] #将之前的统计结果存到outlist列表中
count = 1 #将计算器重置为1
print(outlist) #输出结果
#说明:这里' '的作用是防止string[i+1]这个地方报错
测试输入:
qqqqqqqqqqqddddddddddddvvvvvvvvvusssssssbbbw
输出结果:
11q12d9v1u7s3b1w
可以看到,代码运行起来没有异常,但是又有一个问题产生了,如果所给的数据中重复的字符只有一小部分,而我们只想压缩这一小部分时,就会导致其他的字符被 ‘ 压缩 ’ 得更复杂了,如下面的情况:
测试输入:
jlsdbvbadvbbvbevadfihhbzhvtttttttttttttttjlasdvbjvbjld
输出结果:
1j1l1s1d1b1v1b1a1d1v2b1v1b1e1v1a1d1f1i2h1b1z1h1v15t1j1l1a1s1d1v1b1j1v1b1j1l1d
可以看到,数据被 ‘ 压缩 ’ 之后反而变得更大了,而这并不是我们想要的结果,那我们应该怎么办呢?
第二种情况
(输入数据只有一小部分是重复的,不包含数字)
我们可以把代码稍稍改一下,让单个字母不被压缩:(压缩代码二)
string = input()
string = str(string)+' '
count = 1
outlist = ''
for i in range(len(string)-1):
if string[i] == string[i+1]:
count +=1
else:
if count == 1:outlist +=string[i] #如果只有一个就不写出数字1
else:outlist +=str(count)+string[i]
count = 1
print(outlist)
再次输入上面的数据,得到的结果为:
jlsdbvbadv2bvbevadfi2hbzhv15tjlasdvbjvbjld
这次就达到了我们想要的效果,单个字母没有被压缩,只有真正重复的字母才被压缩了。
看得出来,这两种压缩方式都是无损的,不过相比于第一种压缩代码,我们更想要的是第二种压缩代码,因为第一种代码在输入数据没有重复字符的情况下,程序不但没有压缩数据,反而把数据所占的空间变得更大了,这并不是我们想要的结果。所以,我们就采用第二种压缩代码。
RLE压缩后该如何解压
对于之前提到的第一种代码,博主的解压方式为:(解压代码一)
data = str(input()) #接收数据
outdata = '' #初始化存储输出数据的‘箱子’
box = '' #初始化临时的一个缓冲‘箱子’
for i in data: #遍历接收的数据
if not i.isdigit(): #判断是否为非数字
outdata +=int(box)*i #将结果放到outdata中
box = '' #清空缓冲箱
else:box +=i #如果是数字就直接加到缓冲箱
print(outdata) #打印结果
测试输入:
1a3b20c4d1e
输出结果:
abbbccccccccccccccccccccdddde
效果很好,那么对于第二种压缩方式,对应的解压代码又是什么呢?(解压代码二)
data = str(input())
outdata = ''
box = ''
for i in data:
if not i.isdigit():
if box == '':outdata +=i #判断是否为单个字符,若是就直接加到outdata中
else: #不是单个字符的时候
outdata +=int(box)*i
box = ''
else:box +=i
print(outdata)
其实也就改了一点点,多了一个对单个字母的判断。
整合
现在,我们还需要做的就是整合一下这两个程序,毕竟我们不仅仅只能用cmd去输入字符串数据,我们要压缩的应该是文本文件或者其他的文件。博主已经为大家整合好了,不过为了简便,就没有把程序变成图形化界面了。
效果如下:
以文本方式的解压我就没有展示了,效果是差不多的。
这里面用了一个进度条的程序(很简单的),相关的知识及用法在这里:
Python print 函数 \r 转义字符的玩法及解析——转圈效果、动态表情、小数点加载、进度条_小康2021的博客-CSDN博客
【原创不易啊,整合不易啊,大家点点赞再走呗,如果喜欢,博主强烈推荐你一键三连!!!】