关闭

小量压缩简单算法

156人阅读 评论(0) 收藏 举报
分类:

本方介绍一种简单的数据压缩算法:SB (simple block)

作者:realxie

在对文档进行倒排的时候经常涉及到对倒排文档的压缩,例如假设有单词instance 出现的文档有<1,3 ,4 , 6 ,9 ,10,... >,即倒排表以升充排列,这样我们就可以在倒排文件中只保存前后两个文档位置的差量,即转变之后结果为<1 ,2 , 1 , 2 , 3 , 1 , ...>,因此在遍历的时候可以累积得到每个文档位置。分析转变后的倒排文件我们可知 (不失一般性)保存了更多的小量。如果在内存中我们以一个int类型来保存更多类似于1-10这样的小量就会造成更多的浪费,这是因为1-10可以不超过 4bit的空间来进行存储,而int占用32bit,因此会造成大量浪费。如何压缩数据来节约更多的存储空间有待我们解决。

目前已经有各种各样的算法来解决不量问题:

全局方法:Unary , Binary , r ...

局部方法:Bernoulli , ...其它

纵观各种各样的方法实现起来都是相当的困难,并且具有较高的时间复杂度。

下面我来介绍一种我自己开发,相当简单的一个算法,思想简单,实现简单,运行高效,并且具有相当好的压缩效果,当然不是最后,毕竟简单的背后肯定会 做出一定的牺牲。

算法思想:

首先说明该算法采用不定长编码,设编码的基本块长度为BIT,则每个数字的编码长度为BIT的整数倍。

每个基本块的最后一位为标志位,当最后一位为0时说明编码结束,此时我们可以得到一个整数,相反当最后一位不为0时,则要与后面的基本块一起构成一 个更大的整数。

例如:设BIT = 5;则基本块所能表示的最大值为15,下面给出一些例子

15:-> 11110

7 : -> 01110

现在你可能会问,如果要表示的数大于15怎么办,那我们就使用多个基本块来表示一个数据,此时前面(非最后)基本块的最后一位必须为1,设基本块的 数量为b , 那么最大可以表示的数据为2^(b*(BIT-1))-1,这就是说所有基本块的位除了标志位之外都参与数据的二进制表示。如此:

255:-> 11111 11110

2099: ->10001 00111  00110

解码的时候只需要顺序读入每个基本块就可以确定能否得到一个数据。

本代码高亮显示

  

#include<iostream>
#include<stdlib.h>
#include<string.h>
using namespace std;

#define MAX 0xFFFFFF
#define BIT 4


int buff[MAX];//保存差量数据
int temp[MAX];//保存解码后的结果
char code[MAX];//保存压缩后的结果

int cmp(const void * a , const void * b)
{
       return *(int*)a - *(int*)b;
}


//编码,压缩 
//data,待压缩数据,len侍压缩数据个数
//返回值:压缩后所占位数
int encode(int * data , int len);

//解码
//code ,压缩后的数据 , len:压缩后占用的位数
//data:保存解码后的数据,返回值:解码后数据个数
int decode(char * code , int len , int * data);

//测试数据data需要要多少位可以表示
int bsize(int data);

//将data转换成基本块,b表示data需要b位方可表示出
//return :转换后的数据
int block(int data , int b);

//将一个数据以二进制的形式打印
int print(unsigned int data);

int main()
{

       //////////init
       int t = MAX << 2;
       memset(buff ,0 , sizeof(buff));
       for(int i=0;i<MAX;i++){
              int temp = rand()%t;
              buff[temp>>2] = temp;
       }
       qsort(buff ,MAX , sizeof(int) , cmp);
       int num(0) , i(0);
       while(!buff[i])i++;
       buff[num++] = buff[i++]; 
       for(;i<MAX;i++ , num++)buff[num] = buff[i] - buff[i-1];
       //////////init 上部分只是得到差量数据

       
       int sum = encode(buff , num);
       
       //测试平均所需位数
       cout<<sum * 1.0 / num<<endl;
       int tnum =  decode(code , sum , temp);

       //测试解码后数据是否正确
       for(int i=0;i<num;i++)
              if(temp[i] != buff[i]){
                     cout<<"error:\t"<<i<<"\t"<<buff[i]<<"\t\t"<<temp[i]<<endl;
                     break;
              }
       
       return 0;
}


//计算data需要的字节数
int bsize(int data)
{
       int b = 0;
       while(data) data >>= 1 , b++;
       return b;
}

int block(int data , int b)
{
       int t = (1<<(BIT-1))-1;
       int res = 0;
       for(int i = 0; i<b;i++){
              if(i)t <<= (BIT-1);
              int tmp = data & t;
              tmp <<= (i+1);
              res |= tmp;
       }
       for(int i=b-1;i>0;i--)
              res |= (1<<(BIT*i));
       res <<= (32 - BIT * b);
       return res;       
}

int encode(int * data , int len)
{
       int sum = 0;       
       memset(code , 0 , sizeof(code));
       for(int i=0;i<len;i++){
              int b = bsize(data[i]);
              int l = b/(BIT-1);
              if( b % (BIT-1)) l++;
              int tl = sum >> 3;
              int tm = sum & 7;
              unsigned int tmp = block(data[i] , l);
              if(tm == 0){
                     while(tmp){
                            code[tl] = 0;
                            code[tl] |= tmp >> 24;
                            tmp <<= 8;
                            tl++;
                     }
                     sum += l * BIT;       
              } else {
                     code[tl] |= (tmp >> (24 + tm));
                     tl++;
                     tmp <<= (8-tm);
                     while(tmp){
                            code[tl] = 0;
                            code[tl] |= tmp >> 24;
                            tmp <<= 8;
                            tl++;
                     }
                     sum += l * BIT;
              }
       }
       return sum;
}


int decode(char * code , int sum , int * data)
{
       int p = 0 , res = 0 , bsize = 0 , num = 0;
       num = 0;
       while(p<sum){
              int tb = p >> 3;
              int tm = p & 7;
              int bit = (code[tb]>>(7-tm)) & 1;
              res = (res<<1) + bit;
              bsize ++;p++;
              if(bsize % BIT == 0){
                     res >>= 1;
                     if(bit) continue;
                     else {
                            data[num++] = res;
                            bsize = 0;
                            res = 0;
                     }
              }
       }
       return num;
}

int print(unsigned int data)
{
       if(data == 0)return 0;
       print(data/2);
       cout<<data%2;
       return 0;
}
0
0
查看评论

小量压缩简单算法 .

本方介绍一种简单的数据压缩算法:SB (simple block) 作者:realxie 在对文档进行倒排的时候经常涉及到对倒排文档的压缩,例如假设有单词instance 出现的文档有<1,3 ,4 , 6 ,9 ,10,... >,即倒排表以升充排列,这样我们就可以在倒排文件...
  • FENGQIYUNRAN
  • FENGQIYUNRAN
  • 2015-04-16 15:50
  • 546

一些题目解析

(1)压缩项目进度,会产生下列潜在问题,但         除外A: 项目范围增加B 成本增加C 风险增加D 降低质量确定项目成本答案为A ,进度压缩在没有改变项目范围的情况下进行,以便满足项目目标。(2)关键依赖关...
  • carolzhang8406
  • carolzhang8406
  • 2010-06-15 09:02
  • 771

RLE流压缩——简单算法

简单的说RLE压缩就是将一串连续的相同数据转化为特定的格式达到压缩的目的。  下面都对byte流压缩。  如输入数据  LPBTE pByte={1,1,1,1,1,1};  压缩的数据为6,1  压缩了4个字符。  但...
  • happylife1527
  • happylife1527
  • 2012-09-26 12:28
  • 346

JAVA-简单面试题-算法

2给一个正整数 n, 找到若干个完全平方数(比如1, 4, 9, ... )使得他们的和等于 n。你需要让平方数的个数最少。 给出 n = 12, 返回 3 因为 12 = 4 + 4 + 4。 给出 n = 13, 返回 2 因为 13 = 4 + 9。 package Node...
  • mzj245073253
  • mzj245073253
  • 2016-09-04 11:29
  • 549

机器学习:k-means算法

描述算法接受参数 k ;然后将事先输入的n个数据对象划分为 k个聚类以便使得所获得的聚类满足:同一聚类中的对象相似度较高;而不同聚类中的对象相似度较小。聚类相似度是利用各聚类中对象的均值所获得一个“中心对象”(引力中心)来进行计算的。K-means算法是最为经典的基于划分的聚类方法,是十大经典数据挖...
  • nicky918
  • nicky918
  • 2017-08-18 14:36
  • 280

数据结构及简单算法的总结----之【排序】

为了找工作,把这些玩意好好复习,多多总结下基础知识吧
  • eclipse_c
  • eclipse_c
  • 2014-09-12 19:27
  • 692

[C++算法]六种简单算法

简单算法:冒泡、插入、选择、快速、归并
  • weixin_36381867
  • weixin_36381867
  • 2016-10-26 23:07
  • 1246

简单的面试算法题目

1、编程,用尽可能完整的java语言写一个类,把String作如下转化 hello this is a computer-->computer a is this hello   public static String swapWord(String s)  ...
  • qq_29882585
  • qq_29882585
  • 2016-10-20 21:11
  • 502

九宫格的实现算法

九宫格坐标的小算法:(横坐标:i%横向显示个数的最大值;纵坐标:i/纵向的个数的最大值)
  • HeyLjie
  • HeyLjie
  • 2015-03-31 21:25
  • 231

微分dx、dy是无穷小吗?

微分dx、dy是无穷小吗?在上世纪1930至1970这段时间,数理逻辑模型论取得了快速的发展,比如:哥德尔,A.I. MaltsevLe,Henkin AbrahamRobinson 以及 Alfred Tarski等人的先锋工作。很明显的事实是,在这段时间里,我们掉了队。实际上,A Robinso...
  • yuanmeng001
  • yuanmeng001
  • 2017-09-28 10:00
  • 340
    个人资料
    • 访问:875608次
    • 积分:11841
    • 等级:
    • 排名:第1513名
    • 原创:107篇
    • 转载:1382篇
    • 译文:0篇
    • 评论:57条
    最新评论