zigzag压缩算法运算过程及其传输算法

zigzag 压缩

zigzag 的原理就是压缩多余的因补位造成数据变大的问题,它的原理是把符号位向右移到在最前一位,对负数除最后一位经行求为非;正数求不变.

zigzag 压缩算法代码

/** * 把整数数据转换为zigzag 数据 * @param */
int int_to_zigzag(int n){
     return (n <<1) ^ (n >>31);
}

加密过程演示

zigzag 算法是在apache thriftJAVA版 提取出来的,这里我只是做运算过程的展示,方便大家理解。注意下面的运算我是在16位的2字节经行演示,其他的位数类似。
– (-1)10=转成zigzag的步骤:

  1. 转成二进制:
    11111111_11111111_11111111_11111111
  2. 对2进制符号位无符号右位移到最后一位 :
    11111111_11111111_11111111_11111111
  3. -1 为负数,则对非符号取位非,即为结果:
    00000000_00000000_00000000_00000001

总结:
(-1)10
=(11111111_11111111_11111111_11111111)2
=(00000000_00000000_00000000_00000001)zigzag

  • (1)10=转成zigzag的步骤:

    1. 转成二进制:
      00000000_00000000_00000000_00001010
    2. 对2进制符号位无符号右位移到最后一位 :
      00000000_00000000_00000000_000010100
    3. 1 为负数,则无需变化
      00000000_00000000_00000000_000010100
      总结:
  • (1)10
    = (00000000_00000000_00000000_00000001)2
    = (00000000_00000000_00000000_00000010)zigzag

zigzag 解压

对压缩后的二进制进行解压,需要判断第一位是不是为1,若为1则对除第一位进行位非,然后把第一位进行无符号向左位移到最左一位.

zigzag 解压演示

任然以上面结果进行演示

  • (00000000_00000000_00000000_00000010)zigzag=(11111 =(1)10

    1. 因为符号位(第一位)是0,表示它是正数,所以无需改变位非
      (00000000_00000000_00000000_00000010)
    2. 然后把符号位(第一位)还原移回最后一位去:
      (00000000_00000000_00000000_00000001)2
  • (00000000_00000000_00000000_00000001)zigzag = (11111111_11111111_11111111_11111111)2=(-1)10

    1. 因为符号位(第一位)是1,表示它是负数,所以需要把除第一位作位非:
      ( 11111111_11111111_11111111_11111111)
    2. 然后把符号位(第一位)还原移回最后一位去:
      ( 11111111_11111111_11111111_11111111)2

zigzag 解压算法代码

优化的算法:

/** * 把zigzag 解压位int * @param n zigzag原始数据 */
 private int zigzagToInt(int n) {
    return (n >>> 1) ^ -(n & 1);
  }

代码运算过程演示

  • (00000000_00000000_00000000_00000010)zigzag=(00000000_00000000_00000000_00000001)2 =(1)10

    1. n=00000000_00000000_00000000_00000010
    2. (n >>> 1):n 做无符号右移
      00000000_00000000_00000000_00000001
    3. (n & 1) :n 与1做位与
        00000000_00000000_00000000_00000010 &
        00000000_00000000_00000000_00000001
      =00000000_00000000_00000000_00000000
    4. -(n & 1) :把(n&1)变成负数
       =00000000_00000000_00000000_00000000
    5. (n >>> 1) ^ -(n & 1) 做位异或
      =00000000_00000000_00000000_0000001 ^
        00000000_00000000_00000000_00000000
      =00000000_00000000_00000000_0000001
  • (00000000_00000000_00000000_00000001)zigzag
    = (11111111_11111111_11111111_11111111)2= (-1)10

    1. n=00000000_00000000_00000000_00000001
    2. (n >>> 1):n 做无符号右移
        =00000000_00000000_00000000_00000000
    3. (n & 1) :n 与1做位与
        =00000000_00000000_00000000_00000001&
          00000000_00000000_00000000_00000001
        =00000000_00000000_00000000_00000001
    4. -(n & 1) :把(n&1)变成负数
        =11111111_11111111_11111111_11111110
    5. (n >>> 1) ^ -(n & 1) 做位异或
        =00000000_00000000_00000000_00000001^
          11111111_11111111_11111111_11111110
      = 11111111_11111111_11111111_11111111

zigzag传输

传输算法

单纯的经行压缩,而并不能达到传输字节减少,本来16位的任然用的是16位的传输,32位的任然用32位的传输,因此有必要需要有对应的利用算法.把压缩后的无谓的0减少传输,才能达到压缩减少传输量的的效果.

/** * zigzag 传输算法 * @param n zigzag数据 */
private void write(int n) throws TException {
    //数据缓冲池
   final byte[] temp=null;
   //缓冲数组大小
   int idx = 0;
   while (true) {
      if ((n & ~0x7F) == 0) { //是否剩余8位
        temp[idx++] = (byte)n;
        break;
      } else {
        temp[idx++] = (byte)((n & 0x7F) | 0x80); 取低7位,并在第8位标记1
        n >>>= 7;
      }
    }
    //缓冲池输出 
    //trans_.write(temp, 0, idx);
  }

粗略地解析传输算法是,把zigzag数据分成以7位字节分组,并在第八位插入一位标记位,组成一个8位的普通的传输位数据(TCP/IP最小的传输大小为8位).标记位的作用是表示该字节是否为最后数据字段,若不是则标记为0,若是则标记为1.

代码运算过程演示

  1. 00000000_00000000_00000000_0000001
    =[0000001]
  2. 00000000_00000000_00000001_0000001
    = [1000001,00000001]

传输解密算法

/** * 解密算法 * @param buf 传输过来的字节数组 */
private int read_from_buffer(byte[] buf){
    //结果值
    int result = 0;
    //位移量
    int shift = 0;
    //数组位置
    int off = 0;
    while (true) {
        byte b = buf[off];
        result |= (int) (b & 0x7f) << shift;
        if ((b & 0x80) != 0x80) break;
        shift += 7;
     }
}

传过来的应该是一组存储1 byte 大小的数据的数组.传过来的数据从第0个开始取后7位数字,然后向左位移n*7(n为第几个数组),最后用位或| 连接起来,然后判断当前数组的第8位是不是为0,如果为0则继续,则下一个数组;如果为0,则表示到达最后一个有效数组,结束循环,返回连接好的数据.

代码运算过程演示

  1. [00000001] =00000001
  2. [10000001,00000001] =00000001_00000001

Reference
小而巧的数字压缩算法:zigzag

点赞