目的:通过设计计算机程序,实现基于Lempel-Ziv 算法的英文文本文件压缩。
编码算法思想:
1)建立一个只包含“空前缀串”的字典;将文本文件读入缓冲区,然后将当前编码指针指向第一个字符。
2)从当前编码指针所指的字符开始,用它及后面所有字符作为一个字符串,在字典中查找能与该字符串的前缀匹配的最长前缀串;若没有匹配,则将“空前缀串”的编号0 作为当前码字中的编号部分,再将当前编码指针所指的输入字符“A”作为当前码字中的符号部分。输出当前码字,然后编码指针指向下一个字符;若有匹配的前缀串,则寻找最长匹配的前缀串,然后将该最长匹配前缀串在字典中的编号作为当前码字中的编号部分,再将当前输入序列中,与该前缀串匹配结束后的第一个字符“A”作为当前码字的符号部分。输出当前码字,再将编码指针指向字符“A”之后的第一个字符。
3)将上一步中,最长匹配前缀串加上字符“A”作为一个新的前缀串添加到字典中;若上一步中没有找到匹配的前缀串,则将“空前缀串”加上字符“A”作为新前缀串,实际就是将字符“A”本身添加到字典中。该前缀串编号为现有前缀串的最大编号加一。
4)若输入字符串没有处理完,则回到步骤2),否则结束编码。
说明:1、文本为英文文档。2、文档大小为53kb。
import java.io.*;
import java.time.Duration;
import java.time.Instant;
import java.util.Arrays;
/**
* info
* author:Civil
*/
public class Encode {
static byte[] data;
static int[][] dictionary = new int[65536][2];
static byte[] result = new byte[65536];
static int out_adr = 0;//缓冲区地址起始位置
public static void main(String[] args) {
Instant start = Instant.now();
Coding();
Writing();
Instant end = Instant.now();
long timeElapsed = Duration.between(start, end).toMillis(); // 单位为毫秒
System.out.println("编码完成!");
System.out.println("耗时:" + timeElapsed + "ms");
}
static void Read() {
try {
File infile_path = new File("D:\\学习\\信息论\\题目\\c.txt");
InputStream input = new FileInputStream(infile_path);
data = input.readAllBytes();
input.close();
} catch (Exception e) {
e.printStackTrace();
}
}
static void Coding() {
Read();
dictionary[0][0] = 0;//起始坐标
dictionary[0][1] = 0;//字典长度
byte high_adr = -128;//字典地址0--n个255--高位
byte low_adr = -128;//字典地址1--n个1--低位
byte follow_ele = -128;//后一个
int dic_len = 1;//字典长度
int Max_length = 0;//最长匹配字符串长度
int dic_adr = 0;//字典地址
int length = 1;//匹配字符串实际长度
for (int i = 0; i < data.length; i=i+Max_length+1) {
Max_length = 0;//则匹配长度还原
for (int j = 0; j < dic_len; j++) {
if ((data[i] == data[dictionary[j][0]]) && (dictionary[j][1] > 0)) {//有匹配
//末尾处理
if (i + dictionary[j][1] > data.length) {
continue;
} else {
for (int q = 1; q < dictionary[j][1]; q++) {//判断字典元素与数据流是否相等。如:111是否等于110
if (data[i + q] == data[dictionary[j][0] + q]) {
length++;//实际匹配长度
}
}
if ((dictionary[j][1] > Max_length) && (length == dictionary[j][1])) {//找最长匹配
Max_length = dictionary[j][1];//最长匹配长度
dic_adr = j;//最长匹配的字典地址
}
length = 1;//还原
}
}
}
if ((Max_length == 0) | i == 0) {//空匹配{
high_adr = -128;//byte类型取值范围是[-128,127],所以用-128代表0,用127代表255
low_adr = -128;
follow_ele = data[i];
dictionary[dic_len][1] = 1;
} else {//最长匹配
if (i + Max_length < data.length) {
int ad0;
int ad1;
follow_ele = data[i + Max_length];
ad0 = dic_adr / 256 - 128;//[0,255]转[-128,127]--高位
ad1 = dic_adr % 256 - 128;//低位
high_adr = (byte) (ad0 >> 32);//int转byte
low_adr = (byte) (ad1 >> 32);
//更新字典
dictionary[dic_len][1] = Max_length + 1;
}
}
//输出编码
result[out_adr] = high_adr;
result[out_adr + 1] = low_adr;
result[out_adr + 2] = follow_ele;
//更新字典
dictionary[dic_len][0] = i;
out_adr += 3;
dic_len++;
}
}
static void Writing() {
try {
File outfile_path = new File("D:\\学习\\信息论\\题目\\Coding.txt");
OutputStream output = new FileOutputStream(outfile_path);
byte[] out = Arrays.copyOfRange(result, 0, out_adr);
output.write(out);
output.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}