目录
针对字符的RLE压缩
- 针对纯字符的压缩
- 不考虑两位数及以上的循环
- 例如:用1*2#5*3#表示:11555两个1三个5,即 数*重复次数#
至于为什么只考虑一位数:多位数可以用包装类Integer表示,并且实际压缩中不会单纯压缩字符,一般都是整个对象一起压缩,所以没必要两位相连的数与后面判断
public static StringBuffer RLE(char...chars){//行程编码方法,形参放char型数组
//因为频繁更改字符串,所以返回值不用String
StringBuffer dest = new StringBuffer();
//注意:StringBuffer必须用new,不然不分配空间
//StringBuffer dest = null;会空指针异常
for(int i = 0 ; i<chars.length-1 ; i++){//chars数组遍历——————压缩
//每次轮到chars[i],都需要用if和屁股后面紧跟的元素判断是否相等
dest.append(chars[i]);
dest.append('*');
int count = 1;//相等元素计数器
boolean bo = true;
while(bo){//while循环直到碰不到一样的元素就break
if(i<chars.length-1 && chars[i]==chars[i+1]){//必须要避免空指针异常
//注意:此处对i的判断必须在前,否则角标越界
//并且要用&& 不能用&,否则仍角标越界
count++;
i++;
}else{
bo = false;
}
}
//循环结束,统计相同的个数
dest.append(count);
dest.append('#');//标识符,#之后又开始新的判断
}
return dest;
}
//main方法中实现
String s1 = "1112233334455566777778889999";
StringBuffer s2 = RLE(s1.toCharArray());
System.out.println(s2.toString());
输出结果:1*3#2*2#3*4#4*2#5*3#6*2#7*5#8*3#9*4#
含义为:1出现了3次,2出现了2次......
针对一维对象的RLE压缩
- 对象具有一个属性值和一个坐标值
- 不考虑独立多属性值,因为很难重复
先定义像素点:
public class PixelPoint {//一维像素点
private int grayScale;//灰度值
private int x;//x坐标
public PixelPoint(int grayScale,int x){
this.grayScale = grayScale;
this.x = x;
}
public int getX(){
return this.x;
}
public int getGrayScale() {
return grayScale;
}
}
定义像素点的压缩方法:
public static LinkedHashMap<PixelPoint,Integer> RLE(ArrayList<PixelPoint> px){
//形参放入ArryaList,返回值用LinkedHashMap存储键值对,并且LinkedHashMap可以按添加顺序遍历
LinkedHashMap<ZJH.HJZ.PixelPoint,Integer> linkedHashMap = new LinkedHashMap<>();
for(int i = 0 ; i < px.size() ; ){//
int j = i;
boolean bo = true;
int count = 1;//计相同个数
while(bo){
if(i<px.size()-1){
if(px.get(i).getGrayScale() == px.get(i+1).getGrayScale()){
count++;
i++;
}else{
i++;
bo = false;
}
} else{
bo = false;
i++;
}
}
linkedHashMap.put(px.get(j), count);
}
return linkedHashMap;
}
载入像素点:并使用上面定义好的压缩方法,最后迭代器遍历(完整源码如下)
public class RLE_complex_one {//对一维像素点的RLE算法测试
public static void main(String[] args) {
//此例中所有像素点x坐标连续分布,故暂不考虑排序,用ArrayList效率更高
ArrayList<ZJH.HJZ.PixelPoint> arrayList = new ArrayList<>(20);//初始容量设为20(默认是10,每次扩大1.5X)
//以下模拟像素点的连续排布及灰度值情况
arrayList.add(new PixelPoint(1,1));
arrayList.add(new PixelPoint(1,2));
arrayList.add(new PixelPoint(1,3));
arrayList.add(new PixelPoint(1,4));
arrayList.add(new PixelPoint(1,5));
arrayList.add(new PixelPoint(50,6));
arrayList.add(new PixelPoint(50,7));
arrayList.add(new PixelPoint(50,8));
arrayList.add(new PixelPoint(50,9));
arrayList.add(new PixelPoint(255,10));
arrayList.add(new PixelPoint(255,11));
arrayList.add(new PixelPoint(255,12));
arrayList.add(new PixelPoint(255,13));
arrayList.add(new PixelPoint(255,14));
arrayList.add(new PixelPoint(255,15));
arrayList.add(new PixelPoint(255,16));
arrayList.add(new PixelPoint(255,17));
arrayList.add(new PixelPoint(255,18));
LinkedHashMap<ZJH.HJZ.PixelPoint, Integer> rleDest = RLE(arrayList);//返回编码结果
//以下用迭代器遍历
Set<Map.Entry<PixelPoint, Integer>> entries = rleDest.entrySet();
Iterator<Map.Entry<PixelPoint, Integer>> iterator = entries.iterator();
while(iterator.hasNext()){
int i = 1;
Map.Entry<PixelPoint, Integer> nextentries = iterator.next();
System.out.println("第"+i+"位压缩后的元素的灰度值是:"+nextentries.getKey().getGrayScale()+",且压缩了"+nextentries.getValue()+"个连续的像素点");
i++;
}
}
public static LinkedHashMap<PixelPoint,Integer> RLE(ArrayList<PixelPoint> px){
//形参放入ArryaList,返回值用LinkedHashMap存储键值对,并且LinkedHashMap可以按添加顺序遍历
LinkedHashMap<ZJH.HJZ.PixelPoint,Integer> linkedHashMap = new LinkedHashMap<>();
for(int i = 0 ; i < px.size() ; ){//
int j = i;
boolean bo = true;
int count = 1;//计相同个数
while(bo){
if(i<px.size()-1){
if(px.get(i).getGrayScale() == px.get(i+1).getGrayScale()){
count++;
i++;
}else{
i++;
bo = false;
}
} else{
bo = false;
i++;
}
}
linkedHashMap.put(px.get(j), count);
}
return linkedHashMap;
}
}
这样就把很多个连续的同值像素点压缩成了3个key-value对,数据量巨大的时候压缩效果很明显
针对二维图像的RLE压缩
上面的那个RLE是只考虑了一维的相关性,而考虑二维相关性的算法一般用WBS跳过白块编码,而不用RLE算法
把图像拆分为多个a×a的小方块,这个方块的灰度值相同
按上面的逻辑对方阵进行判断,具体实现十分复杂,matlab和python有现成的库,此文不再对此进行研究。
一维压缩不光可以用于图片处理,对于大量的连续值的数据存储压缩效果都很好