采用VB的编码和解码过程(VB encoding and decoding)

本文介绍了VB(Variable Byte)编码的概念,这是一种利用字节的7位有效编码区进行间距编码的方法。编码过程中,通过延续位标识字节是否为序列的最后一个。解码时,读取延续位为0的字节序列,直到遇到延续位为1的字节。VB编码在实验中实现了对Reuters-RCV1语料库索引超过50%的压缩率,且适用于不同长度的编码单位,如字节、位等。在压缩率和解压速度之间找到了平衡。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

VB(Variable byte, 可变字节)编码利用整数个字节来对间距编码。字节的后7 位是间距的有效编码区,而第1 位是延续位(continuation bit)。如果该位为1,则表明本字节是某个间距编码的最后一个字节,否则不是。要对一个可变字节编码进行解码,可以读入一段字节序列,其中前面的字节的延续位都为0,而最后一个字节的延续位为1。根据上述标识可以把每个字节的7 位部分抽取出来并连接在一起形成编码。图5-8 给出了VB编码和解码的伪代码,表5-4 给出了一个采用VB编码的例子①。
这里写图片描述
这里写图片描述
图5-8 采用VB 的编码和解码过程。div 和mod 函数分别计算整数相除和相除后的
余数。PREPEND 在表头部增加一个元素。比如 PREPREND((1,2),3)=(3,1,2)。
EXTEND 表示将表合并,比如,EXTEND((1,2),(3,4))=(1,2,3,4)


代码实现:

package test3;

import java.math.BigInteger;
import java.util.LinkedList;

public class VariByteCode {
     public static void main(String[] args){
         int n=824;
         System.out.println("测试的间隔大小为"+n);
         LinkedList<String> byteStream=VBEncode(n);
         System.out.println("可变字节码的二进制形式:"+byteStream);                //输出VB编码
         int number=VBDecode(byteStream);
         System.out.println("由可变字节码形式转化为十进制:"+number);              //输出解码后的结果
         n=5;
         System.out.println("测试的间隔大小为"+n);
         byteStream=VBEncode(n);
         System.out.println("可变字节码的二进制形式:"+byteStream);               //输出VB编码
         number=VBDecode(byteStream);
         System.out.println("由可变字节码形式转化为十进制:"+number);              //输出解码后的结果
         n=214577;
         System.out.println("测试的间隔大小为"+n);
         byteStream=VBEncode(n);
         System.out.println("可变字节码的二进制形式:"+byteStream);                 //输出VB编码
         number=VBDecode(byteStream);
         System.out.println("由可变字节码形式转化为十进制:"+number);               //输出解码后的结果
     }
     public static LinkedList<String> VBEncode(int n){                     //我觉得这个算法只能用作自然数的压缩
         LinkedList<String> byteStream=new LinkedList<>();             //创建list存放可变字节码的二进制形式
         LinkedList<Integer> bytes=new LinkedList<>();                 //创建list存放每一步的十进制结果
         //这里把伪代码中的VBEncodeNumber和VBEncode合成一步
         while(true){                          //将运算后的结果放入bytes中,如214577运算后的结果为13,12,49
             bytes.add(0,(n%128));
             if(n<128)
                    break;
             n/=128;
         }
         int lastIndex=bytes.size()-1;        //得到bytes最后一个数的下标
         int lastNumber=bytes.getLast();      //得到bytes最后一个数
         bytes.set(lastIndex, lastNumber+128);   //lastNumber+128,相当于将延续位变为1,如214577运算后的结果为13,12,177
         for(int n1:bytes){
         byteStream.add(toBinary(n1));           //将bytes中的每一个数字变成8位的二进制字符串,并存入byteStream中
         }
         //为了结果方便阅读,这里就不把byteStream中的数据进行合并了
         /*
          * 合并
          * String VBCode="";
          * for(String str:byteStream){
          *    VBCode+=str;                  //VBCode为合并后的结果
          * }
          */
         return byteStream;                  //返回byteStream
     }
     public static int VBDecode(LinkedList<String> bytestream){
         LinkedList<Integer> numbers=new LinkedList<>();     //创建list存放由可变字节码的二进制形式得到十进制数字
         for(String s:bytestream){                           //获取byteStream中的每一个二进制字符串                                   
             BigInteger src = new BigInteger(s, 2);         
             int number=Integer.parseInt(src.toString());    //将二进制字符串变成十进制
             if(number<128)                            //如果小于128直接放入numbers中,否则减去128再放入,相当于把延续位改为0
                 numbers.add(number);
             else
                 numbers.add(number-128);
         }
         int result=0;                                    
         int power=numbers.size()-1;                           //幂次数
         for(int i=0;i<numbers.size();i++){
             result+=numbers.get(i)*Math.pow(128, power);      
             power--;                                          //幂次数--
         }
         return result;                                       //返回结果
     }
     public static String toBinary(int n){
         int[] byteArray = new int[8];                         //新建8位数组
     String binary = Integer.toBinaryString(n);
        for(int i=0;i<8-binary.length();i++)
            byteArray[i]=0;                                     //补足0
        for(int i=0;i<binary.length();i++)
            byteArray[i+8-binary.length()]=binary.charAt(i)-48;  //将binary放入数组的后面
        String result="";
        for(int n1:byteArray){                       //将数组转为字符串
            result+=n1;
        }
        return result;                             //返回字符串
     } 
}

结果为:
测试的间隔大小为824
可变字节码的二进制形式:[00000110, 10111000]
由可变字节码形式转化为十进制:824
测试的间隔大小为5
可变字节码的二进制形式:[10000101]
由可变字节码形式转化为十进制:5
测试的间隔大小为214577
可变字节码的二进制形式:[00001101, 00001100, 10110001]
由可变字节码形式转化为十进制:214577


采用VB 编码压缩,我们在实验中发现,Reuters-RCV1 语料库的索引可以压缩到116MB,
相对于未压缩的索引,压缩率超过了50%
VB 编码的思想也可以应用于比字节更大或更小的单位上,比如32 比特位字、16 比特位字
和4 比特位字(nibble,也称半字节)等等。编码单位越长,那么所需的位操作次数也越少,但
是同时压缩率会降低甚至没有压缩。更短的编码单位会得到更高的压缩率,但同时位操作的次
数也越多。总而言之,以字节为单位在压缩率和解压缩的速度之间提供了一个很好的平衡点。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值