网站首页 > 精选教程 正文
本篇目录
通过阅读本篇文章你可以学习到:
- 什么是LWZ压缩算法
- 发展历程
- 实现思路
- Java代码实现
什么是LWZ压缩算法
LWZ 是一种通过建立字符串字典, 用较短的代码来表示较长的字符串来实现压缩的无损压缩算法, 由 Lempel-Ziv-Welch三人共同创造
发展历程
在信息论之父 C.E.Shannon利用数学语言阐明了概率与数据冗余度的关系之后(1984发表的论文 "A Mathematical Theory of Communication"), 工程技术人员便开始尝试实现具体的算法来进行高效, 快速的压缩.
1952年, D. A. Huffman在论文 "A Method for the Construction of Minimum Redundancy Codes"中提出了计算机界著名的哈弗曼编码: 一种完全依据字符出现概率来构造异字头的平均长度最短的码字的算法.
Hoffman编码效率高, 速度快, 实现方式灵活, 至今仍在数据压缩领域被广泛应用.
但是Hoffman编码仍旧不是数据压缩算法的终点. 1976年, J. Rissanen提出了算术编码, 并在后来跟部分匹配预测模型(PPM)相结合, 开发出了压缩效果近乎完美的算法. 如PPMC, PPMD或PPMZ之类的通用压缩算法都是这一思路的具体实现.
PPM模型和算术编码相结合最大程度地逼近了压缩的极限, 但由于算法的复杂性, 运行速度令人汗颜.
在1977年, 两位思维敏捷的犹太人 J. Ziv 和 A. Lempel 另辟奇径, 完全脱离Huffman及算术编码的设计思路, 创造出了一系列比Huffman编码更有效, 比算术编码更快速的压缩算法, LZ系列算法. 而在1984年, T. A. Welch在其发表的论文"A Technique for High Performance Data Compression"中描述了他对于LZ算法的改进, 也就是本文所讲的LZW算法.
如今, LZ77, LZ78, LZW算法以及他们的各种变体几乎垄断了整个通用数据压缩领域, 我们熟悉的PKZIP, WinZIP, WinRAR等压缩工具都是LZ系列算法的受益者.
实现思路
编码过程
1.初始状态, 用ASCII码表初始化字典. P(previous) 和 C(current)为空
2.读入新的字符C, 与P结合形成字符串 C + P
3.在字典里查找C + P, 如果:
--C+P在字典里, 则令P = C+P
--C+P不在字典里, 将P在字典中的索引输出, 在字典中为C+P建立一个新索引, 更新P = C
4.返回步骤2重复, 直至读完原字符串中所有字符.
解码过程
1.初始状态, 用ASCII码初始化字典. P 和 C为空
2.读入第一个编码, 解码输出
3.赋值P = C, 读入下一个编码并赋值给current
4.在字典中查找current, 如果:
--该编码在字典中
a) 令 s = dict[current]
b) 输出s
c) 新增字典条目 dict[previous] + s[0] (前一个编码的字符 + 当前编码字符的第一个字符)
--该编码不在字典中
a) 令s = dict[previous] + dict[previous][0]
b) 输出s
c) 新增字典条目s
5.返回步骤3重复, 直至读完所有记号.
Java代码实现
import java.util.ArrayList;
public class LZWcompressor {
ArrayList<String> dict;//字典
int dictSize;//字典大小
//初始化字典
public void initDict() {
dict = new ArrayList<String>();
//用ASCII码表初始化字典
for(int i = 0; i <= 255; i++) {
dict.add(String.valueOf(Character.toChars(i)));
}
dictSize = dict.size();
}
//压缩
public String compress(String text) {
//打印输入时内容
System.out.println("压缩前: \n" + text);
initDict();//初始化字典
StringBuilder result = new StringBuilder();//用于存放压缩后的编码
int i = 0;
String previous = "";//存放前字符
String current = "";//存放当前字符
String sumStr = "";//存放P + C
boolean isContain;//是否包含
while(i <= text.length()) {//当读取索引指向字符串外的时候, 停止循环
if(i == text.length()) {//当指针超出字符串时, 说明扫描到了末尾, 则将最后一个字符输出
result.append(String.valueOf(dict.indexOf(previous)));
break;
}
//读入新字符, 并查询是否存在于字典中
current = String.valueOf(text.charAt(i));
sumStr = previous + current;
isContain = dict.contains(sumStr);
if(isContain) {//如果当前字符包含在字典中, 则读取下一个字符并拼接在一起
previous = sumStr;
} else {
dict.add(dictSize++, sumStr);//将这个新字符串添加到字典中
result.append(String.valueOf(dict.indexOf(previous)) + " ");//输出未添加前的字符串的索引
previous = current;//重置previous
}
i++;//指针后移
}
//输出压缩效果
System.out.println("压缩后: ");
System.out.println(result);
// System.out.println("---------字典----------");
// for (int j = 0; j < dict.size(); j++) {
// System.out.println(j + "\t" + dict.get(j));
// }
return result.toString();
}
//解压
public String expand(String target) {
initDict();//初始化字典
//将目标按空格分割
String[] compressed = target.split(" ");
StringBuilder result = new StringBuilder();//用于存储解压后结果
String current = compressed[0];//当前元素
result.append(dict.get(Integer.parseInt(current)));//将第一个元素存入result, 因为第一个元素肯定存在字典中
String previous = current;//前一个元素
boolean isContain;
for (int i = 1; i < compressed.length; i++) {
current = compressed[i];
isContain = dict.contains(dict.get(Integer.parseInt(current)));//判断当前元素是否存在字典中
if(isContain) {//如果存在字典中, 则将当前元素存入result, 并在字典中新增条目
String temp = dict.get(Integer.parseInt(current));
result.append(temp);
//将前一个元素和当前元素的第一位拼接, 存入字典中
String s = dict.get(Integer.parseInt(previous)) + temp.charAt(0);
dict.add(dictSize++, s);
} else {
String s = dict.get(Integer.parseInt(previous)) + dict.get(Integer.parseInt(previous)).charAt(0);
result.append(s);
dict.add(dictSize++, s);//往字典添加条目
}
previous = current;
}
System.out.println("解压后: ");
System.out.println(result.toString());
return result.toString();
}
}
import java.util.ArrayList;
//测试代码
public class test {
public static void main(String[] args) {
LZWcompressor compressor = new LZWcompressor();
String compressed = compressor.compress("HSX is a lovely girl, I love her so much");
String expanded = compressor.expand(compressed);
}
}
/**
输出结果:
压缩前:
HSX is a lovely girl, I love her so much
压缩后:
72 83 88 32 105 115 32 97 32 108 111 118 101 108 121 32 103 105 114 108 44 32 73 264 266 101 32 104 101 114 32 115 111 32 109 117 99 104
解压后:
HSX is a lovely girl, I love her so much
**/
参考:
https://mp.weixin.qq.com/s/UnV3cJAVCXmrWB03jd47GA?forceh5=1
https://mp.weixin.qq.com/s/LdZm0NOhTlNEjiUiTkHj4Q
猜你喜欢
- 2024-11-10 每日分享- jvm 如何压缩 java 项目的可执行文件
- 2024-11-10 15个最好用的JavaScript代码压缩工具
- 2024-11-10 Redis 6.2配置文件全解析:轻松优化缓存性能!
- 2024-11-10 Linux中常用的打包,压缩,解压 tar指令 zip指令
- 2024-11-10 Go发起HTTP2.0请求流程分析(后篇)——标头压缩
- 2024-11-10 hash碰撞的概率和可能性比你直觉中大得多
- 2024-11-10 2020上半年Java面试题总结,20多类1100道面试题...
- 2024-11-10 Facebook 发布最新数据压缩技术:可将 Android App 大小减少 20%
- 2024-11-10 一个简单的字符串,为什么 Redis 要设计的如此特别
- 2024-11-10 Android如何进行资源压缩 android资源文件路径
你 发表评论:
欢迎- 04-11Java面试“字符串三兄弟”String、StringBuilder、StringBuffer
- 04-11Java中你知道几种从字符串中找指定的字符的数量
- 04-11探秘Java面试中问的最多的String、StringBuffer、StringBuilder
- 04-11Python字符串详解与示例(python字符串的常见操作)
- 04-11java正则-取出指定字符串之间的内容
- 04-11String s1 = new String("abc");这句话创建了几个字符串对象?
- 04-11java判断字符串中是否包含某个字符
- 04-11关于java开发中正确的发牌逻辑编写规范
- 最近发表
-
- Java面试“字符串三兄弟”String、StringBuilder、StringBuffer
- Java中你知道几种从字符串中找指定的字符的数量
- 探秘Java面试中问的最多的String、StringBuffer、StringBuilder
- Python字符串详解与示例(python字符串的常见操作)
- java正则-取出指定字符串之间的内容
- String s1 = new String("abc");这句话创建了几个字符串对象?
- java判断字符串中是否包含某个字符
- 关于java开发中正确的发牌逻辑编写规范
- windows、linux如何后台运行jar(并且显示进程名)
- 腾讯大佬私人收藏,GitHub上最受欢迎的100个JAVA库,值得学习
- 标签列表
-
- nginx反向代理 (57)
- nginx日志 (56)
- nginx限制ip访问 (62)
- mac安装nginx (55)
- java和mysql (59)
- java中final (62)
- win10安装java (72)
- java启动参数 (64)
- java链表反转 (64)
- 字符串反转java (72)
- java逻辑运算符 (59)
- java 请求url (65)
- java信号量 (57)
- java定义枚举 (59)
- java字符串压缩 (56)
- java中的反射 (59)
- java 三维数组 (55)
- java插入排序 (68)
- java线程的状态 (62)
- java异步调用 (55)
- java中的异常处理 (62)
- java锁机制 (54)
- java静态内部类 (55)
- java怎么添加图片 (60)
- java 权限框架 (55)
本文暂时没有评论,来添加一个吧(●'◡'●)