小量压缩简单算法
本方介紹一種簡單的數據壓縮算法: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;
}
總結
- 上一篇: Ollydbg中断方法浅探
- 下一篇: boost使用split分割字符串