霍夫曼編碼演算法與實現

2021-07-31 09:12:37 字數 3863 閱讀 1312

一、實驗原理

1. huffman編碼演算法

(1)將檔案以ascii字元流的形式讀入,統計每個符號的發生頻率;

(2)將所有檔案中出現過的字元按照頻率從小到大的順序排列;

(3)每一次選出最小的兩個值,作為二叉樹的兩個葉子節點,將和作為它們的根節點,這兩個葉子節點不再參與比較,新的根節點參與比較;

(4)重複3,直到最後得到和為1的根節點;

(5)將形成的二叉樹的左節點標0,右節點標1,把從最上面的根節點到最下面的葉子節點途中遇到的0, 1序列串起來,得到了各個字元的編碼表示。

2. huffman編碼的資料結構設計

在程式實現中使用一種叫做二叉樹的資料結構實現huffman編碼。

(1)霍夫曼節點結構

typedef

struct huffman_node_tag //節點資料型別

; unsigned

char symbol; //如果是葉節點,那麼它表示某個信源符號,這裡用乙個位元組的8位二進位制數表示

};

} huffman_node;

(2)霍夫曼碼結構

typedef

struct huffman_code_tag //碼字資料型別

huffman_code;

3霍夫曼編碼流程

該程式包括兩個工程,「huff_run」為主工程,其中包括了「huffcode.c」檔案

「huff_code」為庫工程,其中包括了「huffman.c」檔案

下面按照實驗流程來進行分析

3.1 讀入待編碼的原始檔

如下**屬於」huffcode.c」檔案

main(int argc, char** argv)  

} //如果輸入檔案給定,那麼讀取

if(file_in)

} //如果輸出檔案給定,那麼建立

if(file_out)

} //by yzhang for huffman statistics

if(file_out_table)

} //end by yzhang

if(memory) //對記憶體資料進行編碼或解碼操作

//對檔案進行編碼或解碼操作

if(compress) //change by yzhang

huffman_encode_file(in, out,outtable);//step1:changed by yzhang from huffman_encode_file(in, out) to huffman_encode_file(in, out,outtable)

else

huffman_decode_file(in, out);

if(in)

fclose(in);

if(out)

fclose(out);

if(outtable)

fclose(outtable);

return

0;

}

3.2 huffman.c第一次掃瞄,統計信源字元發生頻率

因為是8位元,共256個信源符號,所以建立乙個256個元素的指標陣列,用以儲存256個信源符號的頻率。其下標對應相應字元的ascii碼。需要注意的是,原始檔中不一定所有的信源符號都會出現,因此陣列中存在空元素,而非空元素為待編碼檔案中實際出現的信源符號。

#define max_symbols 256    

//typedef

huffman_node* symbolfrequencies[max_symbols]; //信源符號陣列

//typedef

huffman_code* symbolencoder[max_symbols]; //編碼後的符號陣列

/* 第一次掃瞄,統計信源字元發生頻率 */

static

unsigned

int

get_symbol_frequencies(symbolfrequencies *psf, file *in)

return total_count;

}

(1) 將頻率從小到大排序並建立huffman樹

(2) 遞迴遍歷huffman樹,對存在的每個字元計算碼字

如下**屬於」huffman.c」檔案

static huffman_node*  

read_code_table(file* in, unsigned int *pdatabytes)

count = ntohl(count);

//讀取此編碼表示的資料位元組數

if(fread(pdatabytes, sizeof(*pdatabytes), 1, in) != 1)

*pdatabytes = ntohl(*pdatabytes);

while(count-- > 0) //讀取碼表,由符號、碼長、碼字三部分組成

symbol = (unsigned char)c;

if((c = fgetc(in)) == eof)

numbits = (unsigned char)c;

numbytes = (unsigned char)numbytes_from_numbits(numbits);//計算儲存乙個碼長所需要的位元組數

bytes = (unsigned char*)malloc(numbytes); // 為讀取碼字分配相應的空間

if(fread(bytes, 1, numbytes, in) != numbytes) // 讀取碼字

//根據碼表,進行huffman樹的重建,由根節點至葉節點

for(curbit = 0; curbit < numbits; ++curbit)

p = p->one;

} else

//若當前讀取位為'0'

p = p->zero;

} }

free(bytes);

} return root; // 返回huffman樹的根結點,才可以進行之後的遍歷

}

4.2 讀取huffman碼字,並根據huffman樹進行解碼輸出

如下**屬於」huffman.c」檔案

「` int

huffman_decode_file(file *in, file *out)

} } free_huffman_tree(root); // 所有碼字均已解碼輸出,檔案解碼完畢

return 0;}

二、實驗結果

選擇9種不同格式型別的檔案,使用huffman編碼器進行壓縮得到輸出的壓縮位元流檔案,並對各種不同格式的檔案進行壓縮效率的分析

分析結果如下:

1. **形式表示的實驗結果

2. 各樣本檔案的概率分布圖

3. 實驗結果的分析

可以從**和概率分布圖看出,huffman編碼的平均碼長小於且很接近信源熵,信源熵一定小於8bit/sym

當檔案分布概率越不均勻,編碼效率越高(如yuv檔案);當檔案分布概率比較均勻時,壓縮效果並不理想

霍夫曼編碼

一 八卦 在 演算法為什麼這麼難?這篇部落格裡,劉未鵬講了乙個八卦 根據wikipedia的介紹,霍夫曼同學 當年還在讀ph.d,所以的確是 同學 而這個問題是坑爹的導師robert m.fano 給他們作為大作業的 fano自己和shannon合作給出了乙個suboptimal的編碼方案,為得不到...

霍夫曼編碼

給定乙個文字中出現的一組字元c,每個字元有其出現頻率freq,想構造字元的最優二進位制表示,即用來編碼整個文字的二進位制位最少 定長編碼 每個字元用相同長度的二進位制位數進行編碼,則每個字元的長度n必須滿足,2 n c 變長編碼 思想是賦予高頻字元短碼字,賦予低頻字元長碼字 編碼過程相對簡單,將表示...

霍夫曼編碼

霍夫曼編碼,或者也可以說哈夫曼編碼。它是一種編碼方式,是可變長編碼 vlc 的一種。準確來說,它是一種方法,什麼方法呢?這種方法,它完全依據字元出現的概率來構造異字頭的平均長度最短的碼字。哈夫曼編碼使用變成編碼表對源字元進行編碼,而這個變長編碼表是通過估算源字元出現的概率得到的。它有個特點,就是出現...