网站首页 > java教程 正文
本篇目录
通过阅读本篇文章你可以学习到:
- 什么是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
- 上一篇: 既然内存不值钱,为什么java还要搞一个压缩指针?
- 下一篇: Java压缩算法性能比较
猜你喜欢
- 2024-11-18 一个小技巧,Maven 打 Jar 包体积缩小100倍
- 2024-11-18 两天两夜,1M图片优化到100kb
- 2024-11-18 Java 6 压缩字符串(Compressed String)
- 2024-11-18 Java 9 缩小字符串( Compact String)
- 2024-11-18 java实现对rar压缩包的解压
- 2024-11-18 看了就会:多线程下载图片并压缩,多线程下载能提高效率吗?
- 2024-11-18 Java 9 中的字符串(String)压缩的改进
- 2024-11-18 Java压缩算法性能比较
- 2024-11-18 Spire.PDF for Java 9.3.11 优化了压缩图片时内存的占用
- 2024-11-18 既然内存不值钱,为什么java还要搞一个压缩指针?
你 发表评论:
欢迎- 最近发表
-
- 搞趣网:我的世界全新皮肤包原始居民下载地址
- 我的世界拔刀剑MOD下载(我的世界拔刀剑mod下载国际版)
- 我的世界无正版账号的简单联机方法(非网易版,仅适用于局域网)
- 一些可以显著提高大型 Java 项目启动速度的尝试
- 常见的java敏感异常介绍(java 常见的异常)
- Java 开发者必看!三招实现外部 Jar 包动态加载(含热更新方案)
- Java JAR 启动内存参数配置指南:从基础设置到性能优化
- 对Spring MVC接口进行Mock测试(springmvc对外接口)
- 还在用策略模式解决 if-else?Map+函数式接口方法才是YYDS
- 干掉OpenFeign,SpringBoot 3.0 自带的 HTTP 客户端真香!
- 标签列表
-
- java反编译工具 (77)
- java反射 (57)
- java接口 (61)
- java随机数 (63)
- java7下载 (59)
- java数据结构 (61)
- java 三目运算符 (65)
- java对象转map (63)
- Java继承 (69)
- java字符串替换 (60)
- 快速排序java (59)
- java并发编程 (58)
- java api文档 (60)
- centos安装java (57)
- java调用webservice接口 (61)
- java深拷贝 (61)
- 工厂模式java (59)
- java代理模式 (59)
- java.lang (57)
- java连接mysql数据库 (67)
- java重载 (68)
- java 循环语句 (66)
- java反序列化 (58)
- java时间函数 (60)
- java是值传递还是引用传递 (62)
本文暂时没有评论,来添加一个吧(●'◡'●)