壓縮算法之Elias Gamma Coding & Elias Delta Coding

壓縮算法之Elias Gamma Coding & Elias Delta Coding

Posted by Andrew([email protected])

2013-02-24

基本概念

壓縮算法一般根據應用場景不同可分爲文本壓縮和索引壓縮,後者是搜索引擎的核心技術之一。壓縮的本質是對數據進行重新編碼,編碼依據是數據的分佈特性,一般是概率分佈情況,比如對於倒排索引中的數字編號。數值分佈一般符合指數分佈,均勻分佈,Elias Gamma/Delta主要是基於這兩種分佈的。

壓縮模型可分爲全局模型,局部模型,局部模型參數可動態調整,算法複雜度高,壓縮解壓縮速度慢,但壓縮率高。在編碼方式上可分爲定長和變長編碼。

Elias Gamma/Elias Delta算法適合小整數使用頻率較高的場景。它們都是基於數字分解的算法,都需要使用到下面兩種基本的編碼方式:

1.一元編碼-Unary

主要適合於指數分佈的數值分佈,對於數字N,一元編碼的編碼長度爲N,使用N-1個二進制1和末尾一個0表示,如數字3的一元編碼爲:110

2.二進制編碼-Binary

    主要適合於均勻分佈的數值分佈,對於數字N的二進制編碼,其實就是它在計算機中的實際存儲格式。也就是十進制對應的二進制,如3的二進制爲11。在二進制編碼中,比特寬度會在具體的壓縮算法中不一樣,比如數字3如果用5個比特寬度則爲:00011

Elias Gamma Coding算法過程

1.對於數字x分解成 x=2M

2.對於N+1使用一元編碼

3.對於M使用比特寬度爲N的二進制編碼

    舉例:比如對於數字13,可分解成:13 =2+ 5,即N=3,M=5,則N+1的一元編碼爲:1110;M的比特寬爲3的二進制編碼爲:101,最後的Elias Gamma Coding爲:1110:101.

Elias Delta Coding算法過程

該算法是在Gamma算法基礎上的改進,目的是爲了對N進一步壓縮,可以處理更大的數值。算法過程如下:

1.對於數字x分解成 x=2M

2.對於N+1使用進一步分解成N+1=2N1 M1

2.1. 對N1+1使用一元編碼

2.2. 對M1使用比特寬度爲N1的二進制編碼

3.對於M使用比特寬度爲N的二進制編碼

可以看出,Delta Coding是將Gamma coding的第一個因子再進行了一次Gamma coding。

舉例:對於數字13,可分解成:13=2+ 5,即N=3,M=5,將N+1進一步分解成4=2+ 0,即N1=2,M2=0,所以第一部分編碼爲:110:00,第二部分編碼爲:101,最後的編碼爲:110:00:101.


以下是來自維基百科的Elias Gamma代碼片段,網址:http://en.wikipedia.org/wiki/Elias_gamma_coding

關於Elias Delta可參考:http://en.wikipedia.org/wiki/Elias_delta_coding

Encode

void eliasGammaEncode(char* source, char* dest)
{
    IntReader intreader(source);
    BitWriter bitwriter(dest);
    while (intreader.hasLeft())     
    {
        int num = intreader.getInt();
        int l = log2(num);
        for (int a=0; a < l; a++)
            bitwriter.putBit(false); //put 0s to indicate how many bits will follow
        bitwriter.putBit(true);      //mark the end of the 0s
        for (int a=l-1; a >= 0; a--) //Write the bits as plain binary
        {
            if (num & 1 << a)
                bitwriter.putBit(true);
            else
                bitwriter.putBit(false);
        }
    }
    intreader.close();
    bitwriter.close();
}


Decode

void eliasGammaDecode(char* source, char* dest)
{
    BitReader bitreader(source);
    IntWriter intwriter(dest);
    while (bitreader.hasLeft())
    {
        int numberBits = 0;
        while (!bitreader.getBit() && bitreader.hasLeft())
            numberBits++; //keep on reading until we fetch a one...
        int current = 0;
        for (int a=numberBits-1; a >= 0; a--) //Read numberBits bits
        {
            if (bitreader.getBit())
                current |= bitreader.getBit() << a;
        }
        current |= 1 << numberBits; //leading 1 isn't encoded!
 
        intwriter.putInt(current);
    }
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章