日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

c++ 数据结构 软件压缩/解压缩软件Szip(Huffman算法及应用)

發布時間:2024/3/7 c/c++ 48 豆豆
生活随笔 收集整理的這篇文章主要介紹了 c++ 数据结构 软件压缩/解压缩软件Szip(Huffman算法及应用) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

軟件壓縮/解壓縮軟件Szip(Huffman算法及應用)

完整代碼下載地址

1.需求規格說明

【問題描述】

利用哈夫曼樹編碼進行對已有文件進行重新編碼可以大大提高減小文件大小,減少存儲空間,但是,這要求在首先對一個現有文件進行編碼形成新的文件,也就是壓縮。在文件使用時,再對壓縮文件進行解壓縮,也就是譯碼,復原原有文件。試為完成此功能,寫一個壓縮/解壓縮軟件(控制臺程序,不要求界面)

【基本要求】(60%)

一個完整得系統應具有以下功能:
(1)壓縮準備。讀取指定被壓縮文件,對文件進行分析,建立哈夫曼樹,并給出分析結果(包括數據集大小,每個數據得權值,壓縮前后文件得大小),在屏幕上輸出。
(2)壓縮。利用已建好的哈夫曼樹,對文件進行編碼,并將哈夫曼編碼及文件編碼后的數 據一起寫入文件中,形成壓縮文件(**.Haf)。
(3)解壓縮。打開已有壓縮文件(*.Haf),讀取其中的哈夫曼編碼,構建哈夫曼樹,讀取其 中的數據,進行譯碼后,寫入文件,完成解壓縮。
(4)程序使用命令行方式運行
壓縮命令 :SZip A Test.Haf 1.doc
解壓縮命令:SZip X Test.Haf 2.doc 或 SZip X Test.Haf
用戶輸入的命令不正確時,給出提示。
(5)使用面向對象的思想編程,壓縮/解壓縮、哈夫曼構建功能分別構建類實現。

【提高要求】(40%)

(1)采用不同的數據集,比較其壓縮比,采用最有效的壓縮方式。
(2)多個文件的壓縮。
(3)試構建程序框架,使其能添加新的壓縮/解壓縮算法(例如書上 LZW 壓縮算法)。

2.總體分析與設計

(1)設計思想:

【存儲結構】

1、構建一個哈夫曼樹結點的結構體,其中包括記錄結點權值的數據元素、記錄結點雙親位置及左右孩子位置的數據元素、記錄結點哈夫曼編碼的int型指針、記錄結點哈夫曼樹編碼長度的數據元素。
2、利用動態數組來保存哈夫曼編碼。
3、本題通過構建哈夫曼樹來進行壓縮和解壓縮,當壓縮式即從下至上建樹,解壓縮時即從上至下讀樹。

【主要的算法思想】

本題需要我們運用哈夫曼樹的算法來實現軟件的壓縮和解壓,而壓縮即可以理解為從下至上建樹,解壓縮時即可以理解為從上至下讀樹。
在壓縮時,我們首先要把需要壓縮的文件用二進制的形式打開,然和把其中的字符轉換成ascll碼,然后進行對比,把具有相同ascll碼的字符統計出來進行歸類,并計算同類字符的權重,根據權重從下至上建立哈夫曼樹,再生成哈夫曼編碼(其中,權重大的結點哈夫曼編碼短,權重小的結點哈夫曼編長,),然后把哈夫曼編碼列出來后,8位進1(1Byte=8 Bit),當后面的哈夫曼編碼不足八位時 則要在其后邊進行補0后向進1,然后再將所有的字節輸出到文件中,形成壓縮文件。
在解壓縮時,我們同樣是要把需要解壓縮的文件用二進制的方式進行打開,然后從上至下的讀取哈夫曼樹,讀取哈夫曼編碼,將哈夫曼編碼裝換成編碼前對應的內容,即分別對應哈夫曼樹中結點的內容,這里要注意的是我們讀取的最后一個字節可能是不足8位的,所以我們要注意記錄不足八位時的缺省個數,然后再分別對應哈夫曼樹中的數據,從而實現解壓操作,最后把解壓后的內容輸出即可。
最后編寫計算文件內占用字節大小的函數,再根據占用內存大小計算壓縮率;然后通過對比壓縮前和解壓后文件內每個字符是否一致來判斷解壓前和解壓后的文件內容是否完全一致。

(2)設計表示:


(3)詳細設計表示:

1、countFrequency()統計字符出現次數
首先以二進制方式打開文件,然后讀取其中的字符,判斷這個字符是否是第一次出現,如果是就把它初始化,然后葉子結點總數加一要是不是第一次出現,就把權值加1。
2、createHuffmanTree()建哈夫曼樹
先找出兩個權值最小的結點然后建樹,一直到最后只有一棵樹,為了減少壓縮文件中需要寫入的huffman樹的信息,約定小標小的結點做為雙親結點的左孩子。
3、calculateCode() 計算哈夫曼編碼
從下往上一直找到根節點,然后一層一層加,計算哈夫曼的長度然后再從上往下找,左孩子編碼0,右孩子編碼1。
4、addBit(int bit)對一個未滿8bit的byte中加入一個bit
如果新增的為0,直接就左移;如果新增為1,就先左移然后與1按位或。
5、resetByte()將byte清空
將byte與byte中bit的個數都賦值0,即清空。
6、doCompress(…)壓縮函數
調用前面編寫的函數,首先計算每個字符的權值,再根據權值大小建立哈夫曼樹,再給樹上的結點進行哈夫曼編碼,然后把哈夫曼樹從上之下將結點位置寫入輸出文件;將字符的哈夫曼編碼寫入byte中,即八位算一字節,如果滿了就輸出字節,并將原字節清空,然后把不足8位的后面補0,然后輸出,再清空。
7、doDecompress(…)解壓函數
首先讀出根節點的位置,然后確立各個幾點之間的雙親關系(先左后右),然后方便讀取 將數據放入隊列,由于在壓縮的時候是從上之下存入到文件當中的 所以這個時候直接依此彈出隊頂元素即可實現從上至下讀樹,然后八位一循環,分別與哈夫曼樹的左右孩子進行比較,找出哈夫曼編碼最后一個字原本對應的內容,注意最后不足8位的字節要單獨處理。

3.編碼

1、編碼過程中遇到一些問題,在建立huffman樹時不知如何在壓縮過程中同時進行編碼和建樹,不知如何存放編碼,編碼必須要存儲才能建立有效的huffman樹。后來想到可以用動態數組保存huffman編碼,由于編碼長度不定,用動態數組可以彌補這個空缺。
2、對于不滿足八位的字符,最開始沒預想到這種情況,壓縮過程中出現錯誤,后來通過同學的提醒,才意識要進行補位的操作。若新增的bit為0,則直接將byte按位左移;新增的bit為1,先將byte按位左移,再與1按位或運算的規律進行補位操作。補位時,還需要預留一個字符,等壓縮完后在該位置寫入不足一個byte的bit個數。
3、在測試過程中,解壓縮后的文件總是會比原文件大一點,而文件內容的最后總會出現一些亂碼,后來通過調試和查找相關資料,我明白了,在ofstream中自帶一種文件流指針,便于我們讀取文件中的字符,在我壓縮的過程當中,壓縮到最后,這個文件流指針就走到了文件的最后,而該指針占用一i定的內存,所以在壓縮過程中把該指針也進行了壓縮,解壓縮時自然也輸出了該指針,所以會出現解壓縮后的文件要比原文件大,所以我在壓縮函數中增加了ofsFile.seekp(0, ios::beg);函數,將寫指針移動到文件開頭,從而解決了該問題。

4.程序及算法分析

【使用說明】


輸入文件存儲的位置,壓縮/解壓縮文件
(寫博客的時候才發現,我這里給的執行命令好像和老師要求的執行命令不一樣,不過是小問題哈哈,讀者私下自己改一下好了😁)

【測試數據】

1、壓縮文件



2、解壓縮文件


3、對比原文件與解壓縮后的文件



【討論與分析】

Huffman壓縮以字節為單位進行壓縮,將8個bit作為一個byte,通過對bit進行操作,以達到壓縮與解壓的目的

【改進設想】

1、我現在只實現了基本要求,沒能實現多個文件的同時壓縮
2、我的壓縮算法不是很好,以至于我的壓縮率比較大,日后還需要多多學習才能逐步提高自己的能力

5.附錄

【壓縮函數核心代碼】

//壓縮函數 成功執行返回 true 失敗 false bool HuffmanTree::doCompress(char *pcInput, char *pcOutput) {if (!countFrequency(pcInput)) //如果不能計算字符出現的次數就返回false 可以計算就繼續執行程序return false;createHuffmanTree();calculateCode();ifstream ifsFile;ofstream ofsFile;ifsFile.open(pcInput, ios::binary);ofsFile.open(pcOutput, ios::binary);char c;if (!ifsFile){cout << "Unable to open the file" << pcInput << '!' << endl;return false;}if (!ofsFile){cout << "Unable to open the file" << pcOutput << '!' << endl;return false;}//輸出huffman編碼/*while (ifsFile.get(c)){ int _nTem = c + 128;for (int i = 0; i < HT[_nTem].nCodeLenght; i++){ofsFile << HT[_nTem].pnCode[i] << endl;}}*/ofsFile.put(0); //預留一個字符,等壓縮完后在該位置寫入不足一個byte的bit個數ofsFile.put(mnRoot - 384); //將根節點的位置-384寫入(為使該值不超過char的最大表示范圍)//384=256+128for (int i = 0; i<nLeaf * 2 - 1; i++) //從上往下{ //寫入每個結點的雙親結點位置if (HT[i].nParent == -1) //若該節點沒有雙親結點,則寫入127(一個字節所能表示的最大值2?-1=128-1=127)ofsFile.put(127);else //否則將雙親結點的位置-384再寫入(為使該值不超過char的最大表示范圍)ofsFile.put(HT[i].nParent - 384);}while (ifsFile.get(c)){ //將字符的huffman編碼并加入byte中int _nTem = c + 128;for (int i = 0; i < HT[_nTem].nCodeLenght; i++){//ofsFile.put(HT[_nTem].pnCode[i]);addBit(HT[_nTem].pnCode[i]); //將字符的huffman編碼并加入byte中if (mnBitsNum == 8){ //若byte已滿8位,則輸出該byte并將byte清空ofsFile.put(mcByte);resetByte();}}}if (mnBitsNum != 0){//滿足8位的前面已經通過resetByte()函數清空了 mbitsNum置為0 而不滿足8位的執行下面語句//處理最后未滿8個字符的byte,用0填充并記錄填充的個數for (int i = mnBitsNum; i<8; i++){addBit(0);mnLackNum++;}ofsFile.put(mcByte); //再輸出and清空resetByte();}ofsFile.seekp(0, ios::beg); //將寫指針移動到文件開頭(文件流指針)ofsFile.put(mnLackNum); //寫入最后一個字節缺失的bit個數ifsFile.close();ofsFile.close();return true; }

【解壓縮函數核心代碼】

//解壓縮函數 成功執行返回 true 失敗 false bool HuffmanTree::doDecompress(char *pcInput, char *pcOutput) {queue<char> q;char c;ifstream ifsFile;ofstream ofsFile;ifsFile.open(pcInput, ios::binary);ofsFile.open(pcOutput, ios::binary);if (!ifsFile){cout << "Unable to open the file" << pcInput << '!' << endl;return true;}if (!ofsFile){cout << "Unable to open the file" << pcOutput << '!' << endl;return false;}ifsFile.get(c);mnLackNum = c; //讀出最后一個字節缺失的bit個數ifsFile.get(c);mnRoot = c + 384; //讀出根結點的位置for (int i = 0; i < nLeaf * 2 - 1; i++){ //建立各結點之間的雙親孩子關系ifsFile.get(c);if (c == 127) //等于127->根節點continue;else{HT[i].nParent = c + 384;if (HT[c + 384].nLeftChild == -1)//雙親孩子關系——先左后右HT[c + 384].nLeftChild = i;elseHT[c + 384].nRightChild = i;}}int _nPoint = mnRoot;//為了方便處理最后一個可能有缺失bit的字節,先將讀出的數據放入隊列while (ifsFile.get(c))q.push(c);//還原文件過程while (q.size()>1){ //還未到最后一個字節c = q.front(); //返回隊頂元素for (int i = 0; i < 8; i++){ //先左后右if (int(c & 128) == 0){_nPoint = HT[_nPoint].nLeftChild;//這個左孩子沒有左孩子也沒有右孩子就把這個輸出if (HT[_nPoint].nLeftChild == -1 && HT[_nPoint].nRightChild == -1){ofsFile.put(char(_nPoint - 128));_nPoint = mnRoot; //更新}c = c << 1;}else{_nPoint = HT[_nPoint].nRightChild;if (HT[_nPoint].nLeftChild == -1 && HT[_nPoint].nRightChild == -1){ofsFile.put(char(_nPoint - 128));_nPoint = mnRoot;}c = c << 1;}}q.pop(); //彈出隊頂元素}c = q.front(); //最后一個字節for (int i = 0; i < 8 - mnLackNum; i++) //原理同上{if (int(c & 128) == 0){_nPoint = HT[_nPoint].nLeftChild;if (HT[_nPoint].nLeftChild == -1 && HT[_nPoint].nRightChild == -1){ofsFile.put(char(_nPoint - 128));_nPoint = mnRoot;}c = c << 1;}else{_nPoint = HT[_nPoint].nRightChild;if (HT[_nPoint].nLeftChild == -1 && HT[_nPoint].nRightChild == -1){ofsFile.put(char(_nPoint - 128));_nPoint = mnRoot;}c = c << 1;}}q.pop();ifsFile.close();ofsFile.close();return true; }

注:點擊此處下載源代碼程序包,感謝閱讀~

總結

以上是生活随笔為你收集整理的c++ 数据结构 软件压缩/解压缩软件Szip(Huffman算法及应用)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。