天天看點

huffman樹_huffman 霍夫曼無損編解碼 c++ 壓縮

huffman樹_huffman 霍夫曼無損編解碼 c++ 壓縮

PS:本文章僅作為個人學習筆記,參考link均已貼出,

如侵告删!

huffman原理:哈夫曼(huffman)樹和哈夫曼編碼 - dashuai的部落格 - 部落格園

推薦關注的專欄:

資料編碼​www.zhihu.com

huffman樹_huffman 霍夫曼無損編解碼 c++ 壓縮

說明:為友善描述,将被編碼的每一資料,用 ‘字元’代稱

建構霍夫曼樹,左子樹值為0,右子樹值為1. 将出現頻率大的‘字元’放在離根節點近的位置,出現頻率小的‘字元’放在離根節點稍微遠的位置。這樣,對于一串‘字元’,就可以實作用最短的序列‘表示’總‘字元’串資訊,節省需要使用的01串,實作資訊壓縮。

建構哈夫曼樹的兩個準則:

每次組合目前序列中權值(就是‘字元’出現的頻率/數)最小的兩個節點,分别作為左右子節點,合并得到父節點。父節點的權值,為左右子節點的權值和。'抹掉'這兩個合并了的節點,得到的父節點繼續參與後續的建構樹過程;

霍夫曼樹中,每一個葉子節點代表一個被編碼的值,也即‘字元’。任意葉子節點不可出現在其他葉子節點的路徑中(因為根據霍夫曼樹進行‘字元’編譯,是以葉節點為終點的,下面會細說。)

根據霍夫曼樹編譯‘字元串’:

每次從根節點出發,往左子樹走代表0,往右子樹走代表1.直到遇到葉子節點,就完成了一次一個‘字元’的編碼。是以上面說的,任意葉節點不可出現在其他葉節點的路徑中。因為如果出現了,這個在‘别人’路徑中的‘字元’節點,就沒法被編碼到咯,這是不可的。

清晰且注釋詳細的huffman代碼傳送門:https://zhuanlan.zhihu.com/p/144562146

Q:

n個葉子節點(待編碼‘字元’個數為n),需要建構多大的霍夫曼樹?

A:

2n-1 考慮從霍夫曼樹的建構過程了解這個結果。因為每一次左右子節點合并,會獲得一個新的父節點,節點數+1. 對于n個葉子節點,需要進行n-1次計算(這很好了解吧,n個數的序列可産生n-1次不重複順序運算),是以可新增n-1個節點,故樹的總結點樹變為:n+(n-1)=2n-1

代碼實戰部分:

一小段c++并發優化速度

代碼獻給大家~.~:

/**
           

參考自:https://github.com/ningke/huffman-codes

有了上面的壓縮代碼,我們可以開始愉快的壓縮大多數的 string 序列了(像:英文文章這樣的長篇大論.)。可以發現,對待輸入資料,我們使用 string 資料類型接收~

不過你可能還會遇到,需要壓縮一些數值序列,像 {10, -19, -200, 333 ...},這樣的資料存在符号,且元素值不止包含一位(比如 '10','-200‘ 這類資料,不能被拆分成 ‘1’ ’0‘ / ’-‘ ’2‘ ’0‘ ’0‘ 來"孤立"壓縮...破壞資料“特征”了..)。針對此類場景,我們需要使用 vector<int> 資料類型接收輸入資料,以上代碼在對應函數處,将 string 換成 vector<int> 就好。另外對于輸入資料的“流入”方式,還是采用'.txt'檔案,不同元素間用 ' , ' 隔開,做以下處理:

#include 
           

這樣就可以把有符号,且元素位數超過一位的資料,“送入” huffman 算法進行編解碼,完成壓縮恢複啦~

既然都到這一步了,那我猜你肯定還會遇到python代碼調用這個huffman c++編解碼子產品的問題咯~ 可以把這個 c++ 子產品編譯成動态庫 --> .so檔案,供給python調用。對于傳入資料,可以是 .txt (如上面的實作),也可以是 .npy (對你沒有看錯,c++裡也可以直接讀寫.npy,甚至把npy讀入記憶體再高效傳給c++都行)。請看這裡: https://www.zhihu.com/question/293053840/answer/1434974446

得到.so庫後,難免要做一些傳參工作,這裡我又遇到了一點小坑,給大家排了吧:

參考了: https://segmentfault.com/q/1010000010680269

import 
           

碼字不易,可以麻煩點了贊再走嘛 ~.~

繼續閱讀