国产日韩欧美一区二区三区三州_亚洲少妇熟女av_久久久久亚洲av国产精品_波多野结衣网站一区二区_亚洲欧美色片在线91_国产亚洲精品精品国产优播av_日本一区二区三区波多野结衣 _久久国产av不卡

?

基于哈夫曼編碼的多線程無損壓縮庫的設(shè)計(jì)與實(shí)現(xiàn)

2019-10-16 09:07彭海峰劉永紅趙衛(wèi)東成都大學(xué)信息科學(xué)與工程學(xué)院四川成都6006成都大學(xué)模式識別與智能信息處理四川省高校重點(diǎn)實(shí)驗(yàn)室四川成都6006
關(guān)鍵詞:壓縮率字符字節(jié)

鄢 濤, 彭海峰, 李 浩, 陳 超, 劉永紅, 趙衛(wèi)東(.成都大學(xué) 信息科學(xué)與工程學(xué)院, 四川 成都 6006;2.成都大學(xué) 模式識別與智能信息處理四川省高校重點(diǎn)實(shí)驗(yàn)室, 四川 成都 6006)

0 引 言

程序開發(fā)中,文件操作是比較常用的操作.除了創(chuàng)建、刪除及讀寫操作外,壓縮或解壓也很重要.目前,開發(fā)具有壓縮功能的程序比較常用的函數(shù)庫有7z、LZ4、QuickLZ及snappy等,但是這些庫普遍存在不開源、嵌入到自己的項(xiàng)目中不夠便捷等問題.對此,本研究介紹了一種基于哈夫曼樹的多線程壓縮C++庫.該庫以哈夫曼編碼為基礎(chǔ),實(shí)現(xiàn)了基本的無損壓縮,同時保證了良好的壓縮率,并且使用C++的多線程實(shí)現(xiàn)了高效的壓縮速度,能夠滿足實(shí)際開發(fā)中高效敏捷的開發(fā)需求.文件壓縮通常分為無損壓縮與有損壓縮.壓縮軟件通常用的都是無損壓縮,無損壓縮又分為2種:一種是將數(shù)據(jù)替換成數(shù)據(jù)加重復(fù)次數(shù),另一種是用較短的數(shù)來替換較長的數(shù)[1].本研究使用第2種方法,由此能有效地求出所有數(shù)據(jù)的帶權(quán)編碼最小的前綴編碼方式,同時,將采用C++的多線程來處理壓縮數(shù)據(jù)過大的情況,在保證壓縮率時提高壓縮的速度.

1 無損壓縮與哈夫曼樹

1.1 無損壓縮的原理

1.1.1 無損壓縮.

無損壓縮是指利用數(shù)據(jù)的統(tǒng)計(jì)冗余進(jìn)行壓縮,可完全恢復(fù)原始數(shù)據(jù)而不引起任何失真,但壓縮率是受到數(shù)據(jù)統(tǒng)計(jì)冗余度的理論限制,一般為2∶1到5∶1.這類方法廣泛用于文本數(shù)據(jù)、程序和特殊應(yīng)用場合的圖像數(shù)據(jù),如指紋圖像、醫(yī)學(xué)圖像等,的壓縮[2].現(xiàn)在常用的壓縮軟件都是無損壓縮.

1.1.2 無損壓縮方式.

方式1:將數(shù)據(jù)替換成數(shù)據(jù)+重復(fù)次數(shù).例如,某個文件的內(nèi)容是AAAABBBCCCCC,就可以替換為4A3B5C,將12個字符壓縮為6個字符,大大減少了存儲空間,但是這種壓縮比較適用于重復(fù)性大且連續(xù)重復(fù)的情況.

方式2:用更短的數(shù)來替換較長的數(shù).在計(jì)算機(jī)中所有的數(shù)據(jù)都會以二進(jìn)制進(jìn)行存放,文件里所有的字符、數(shù)字,在計(jì)算機(jī)里都表現(xiàn)為數(shù).將每次出現(xiàn)的字符根據(jù)出現(xiàn)的權(quán)重用二進(jìn)制的1位或幾位進(jìn)行替換,這樣1個字節(jié)就能存儲多個字符,減少了普通編碼文件所占的空間大小.

1.2 哈夫曼樹建立

1.2.1 統(tǒng)計(jì)每個字符出現(xiàn)的頻率.

若要建立哈夫曼樹,首先要計(jì)算出該文檔中每個字符出現(xiàn)的頻率,然后根據(jù)出現(xiàn)的頻率給每個字符賦予權(quán)值.假設(shè)該文檔中有A、B、C與D 4個字符,出現(xiàn)的次數(shù)依次是10、8、5與4次,然后可以給A、B、C與D根據(jù)出現(xiàn)的次數(shù)賦予編碼.偽代碼如下:

void analyse(char * fileName)

{

while ((fread(&temp,1,1,fp))==1)//fp為該文件的指針

{

int flagExist=0;

//判斷該字符之前出現(xiàn)過沒有?

check(flagExist);

//沒有出現(xiàn)過

if (!flagExist)

save(temp);//存儲該字符

}

fclose(fp);

}

1.2.2 根據(jù)字符出現(xiàn)的頻率建立哈夫曼樹.

先簡單介紹一下前綴編碼,前綴編碼是指任一字符的編碼都不是另一個字符編碼的前綴,這種編碼翻譯時不會出現(xiàn)歧義.哈夫曼編碼是一種帶權(quán)路徑最小的前綴編碼[3],非常適用于文件壓縮.獲取哈夫曼編碼的偽代碼如下:

void createCoding(FileState * pfileState)

{

//建立根節(jié)點(diǎn)

node * root=createHuffman(pfileState);

//創(chuàng)建哈夫曼樹

fillHuffmanCode(root,pfileState);

//獲取哈夫曼編碼

int i,j;

for(i=0;isymbolCount;i++)

{

printf(″%c″,pfileState->symbolArray[i].character);

for(j=0;j<20;j++)

printf(″%d ″,pfileState->symbolArray[i].huffCode[j]);

}

}

其中,F(xiàn)ileState為文件字符總結(jié)構(gòu)體,有文件中總字符數(shù)及每個出現(xiàn)的字符數(shù)字2個屬性.

本研究需要先建立哈夫曼樹,每次依次尋找節(jié)點(diǎn)數(shù)組中最小的2個數(shù),然后將其組建成一個二叉樹,直到讓所有的節(jié)點(diǎn)都組建到這棵二叉樹上為止,然后根據(jù)哈夫曼樹對左右兩邊的節(jié)點(diǎn)賦予編碼,即得到哈夫曼編碼.注意,用1、2進(jìn)行編碼而不是0、1,因?yàn)?可能會與一個字節(jié)初始的0產(chǎn)生混淆,所以用2來代替,在壓縮和解壓時需要把2替換成0,以便進(jìn)行位的操作[4].

2 文件的壓縮與解壓

2.1 文件的壓縮

根據(jù)獲取的哈夫曼編碼來讀文件,將讀到的數(shù)據(jù)按編碼進(jìn)行替換,再用C++的位操作將每個字符的0、1編碼合成1個字節(jié),再存到文件中,這樣1個字節(jié)就可以存儲多個字符,從而達(dá)到壓縮效果.偽代碼如下:

void compressor(char * fileName,char * newFileName)

{

//打開文件

ostream outFile;

if (outFile.open(fileName,ios::out)==0)

{

cout<<″打開失敗″<

return;

}

ostream inFile;

if (inFile.open(newFileName,ios::in)==0)

{

cout<<″打開失敗″<

return;

}

//將字典結(jié)構(gòu)體先寫到文件里面,方便解壓時讀取

writeHeader(fp2,pfileState);

//根據(jù)字典對文件重新編碼實(shí)現(xiàn)壓縮效果

writeCode(fp1,fp2,pfileState);

outFile.close();

inFile.close();

}

本研究修改文件的后綴為ycf,即Linux下的壓縮文件格式,然后對照著編碼表,將每個字符翻譯成二進(jìn)制中的位,再用C++中的位操作將這些位合成字節(jié)實(shí)現(xiàn)壓縮.

2.2 文件的解壓

解壓過程正好與壓縮過程相反.解壓過程是,依次讀取文件中每個字符,然后根據(jù)字符的二進(jìn)制對照哈夫曼編碼進(jìn)行翻譯,將翻譯的結(jié)果存儲到指定的文件中,這樣就完成了解壓[4].解壓偽代碼[5-6]如下:

void deCompress(char * fileName,char * newFileName)

{

memset(&fileState,0,sizeof(fileState));

//讀取文件獲得相關(guān)信息存儲到fileState中

readHeader(fileNmae, & fileState);

//創(chuàng)建哈夫曼樹

node * root=NULL;

root=createHuffman(&fileState);

//翻譯哈夫曼編碼得到新的解壓文件

writeDeCompressfile(fp,fileName,root,newFileName);

}

解壓時,先讀取文件,然后依次翻譯當(dāng)中的每個字節(jié),將字節(jié)中的位翻譯成字符,因?yàn)楣蚵幋a是一種前置編碼,在翻譯過程中不會產(chǎn)生歧義,這樣讀完整個文件即可完成解壓過程.

3 優(yōu)化、封裝與性能測試

3.1 多線程優(yōu)化

如果處理的文件較大,則單線程的設(shè)計(jì)模式效率就會很低.壓縮一個文件可能需要幾分鐘甚至更久,由于這么長的壓縮時間不能滿足實(shí)際開發(fā)需要,所以必須要引入多線程的設(shè)計(jì)模式[7-8].本研究使用C++11的多線程開發(fā)加快壓縮速率.壓縮過程的偽代碼如下:

void compress(char * fileName,char * newFileName)

{

//用2個線程讓分析文件與創(chuàng)建哈夫曼編碼同時進(jìn)行

std::thread th1(analyse,fileName);

std::thread th2(createCoding, & fileState);

//阻塞主線程

th1.join();

th2.join();

writeFile(fileName, & fileState,newFileName);

}

本研究使用C++11庫中的thread類來進(jìn)行并發(fā)操作,同時使用2個線程讓分析文件與創(chuàng)建哈夫曼樹同時進(jìn)行,這樣能大大加快壓縮速度.

3.2 封裝成庫

封裝成靜態(tài)庫的過程很簡單,只需要調(diào)節(jié)項(xiàng)目的相關(guān)屬性,再生成項(xiàng)目即可.庫封裝好之后,調(diào)用庫中函數(shù)的步驟如下:

1)更改項(xiàng)目的相關(guān)屬性,導(dǎo)入庫;

2)引入頭文件,應(yīng)用相關(guān)函數(shù)進(jìn)行壓縮或者解壓,代碼如下:

//引入頭文件

#include

#include

#include

int main(int argc, char ** argv)

{

ycl::compressor t;//定義庫中的壓縮類

std::string op,tar;

//被壓縮的文件絕對路徑名及壓縮后的文件名

std::cin >> op >> tar;

t.compress(op,tar);//壓縮

t.deCompress(op,tar);//解壓縮

return 0;

}

本研究以7z的庫為例介紹如何用7z庫函數(shù)進(jìn)行壓縮與解壓縮.由于7z的庫中沒有現(xiàn)成的壓縮函數(shù),而且開源社區(qū)也只有7z的源代碼,程序員需要自己編譯成靜態(tài)庫,然后導(dǎo)入到自己的項(xiàng)目中,具體步驟如下:

1)從網(wǎng)絡(luò)下載源代碼,用VS對其編譯成靜態(tài)庫;

2)新建自己的項(xiàng)目導(dǎo)入編譯好的靜態(tài)庫;

3)編寫壓縮與解壓函數(shù).這個過程非常麻煩,因?yàn)樾枰畮熘兴泻瘮?shù),才能將其應(yīng)用到自己的函數(shù)中,這將大大降低開發(fā)的效率,增加不必要的開發(fā)難度與時間消耗[9].

3.3 性能測試分析

封裝好庫后,在Windows平臺下分別對圖片、文本文檔及視頻等常用文件進(jìn)行大量的數(shù)據(jù)測試,因?yàn)閷?shí)際開發(fā)中所要壓縮的文件大小都是以MiB為單位,所以本研究的測試文件都為1 MiB到1 GiB之間的文件.為了保證數(shù)據(jù)的可靠性,每種文件的樣本數(shù)量為100,由于手動壓縮文件較麻煩,本研究先把文件存在文件夾中,然后用C語言循環(huán)遍歷此文件夾進(jìn)行壓縮.

測試壓縮率如表1所示.

表1 測試壓縮率

表1中的文件大小都為樣本容量中的平均文件大小.從表1可知,本研究設(shè)計(jì)的庫的壓縮率與現(xiàn)有的庫還有一定的差距.但是,在CSDN、掘金、博客園等論壇上尋找的近100份問答中,一般情況下,本研究所探討的壓縮率已經(jīng)能完全符合實(shí)際開發(fā)的需求,同時使用起來簡單便捷,然而使用7z的平均學(xué)習(xí)時間是8 h左右,但使用本研究的庫最多需要2 h的學(xué)習(xí)時間,且不需要繁瑣的導(dǎo)入過程,開發(fā)效率高.

4 結(jié) 語

本研究討論了利用哈夫曼編碼的多線程壓縮程序.實(shí)驗(yàn)表明,哈夫曼編碼的壓縮方法具有良好的壓縮率,缺點(diǎn)在于需要耗費(fèi)大量時間,所以在庫中加入了C++11中的多線程,這樣大大縮短了壓縮時間.簡潔的庫也保證了程序員使用過程中的便捷,相對于目前常用的庫較大地提高了開發(fā)效率,同時對研究文件壓縮過程和壓縮算法的改進(jìn)具有一定的參考意義.

猜你喜歡
壓縮率字符字節(jié)
No.8 字節(jié)跳動將推出獨(dú)立出口電商APP
字符代表幾
一種USB接口字符液晶控制器設(shè)計(jì)
圖片輕松變身ASCⅡ藝術(shù)畫
No.10 “字節(jié)跳動手機(jī)”要來了?
HBM電子稱與西門子S7-200系列PLC自由口通訊
基于MSP430的四旋翼飛行器的S-BUS通信協(xié)議的設(shè)計(jì)與實(shí)現(xiàn)
水密封連接器尾部接電纜的優(yōu)化設(shè)計(jì)
纏繞墊片產(chǎn)品質(zhì)量控制研究
某型飛機(jī)靜密封裝置漏油故障分析