哈弗曼編碼的本質是將檔案中出現頻率越高的字元用越短的二進位製碼代替從而達到節省空間的目的。為了達到這個目的,需要構建哈夫曼樹。
哈弗曼樹的構建過程為:
1. 將原始檔所有字元及其出現次數構建哈弗曼節點
2. 將權值最小的兩個節點作為左右葉子節點組成乙個新的哈弗曼節點來替代原哈弗曼節點集合中的這兩個節點
3. 重複步驟2直至只剩乙個哈弗曼節點,則該節點為哈夫曼樹
而每個節點的哈弗曼編碼為哈夫曼樹的根節點到該節點所經過的路徑編碼:每經過一次左孩子則在後面新增編碼「0」,每經過一次右孩子則在後面新增編碼「1」,直至到達該節點。此時累計的0和1組成的編碼即為該節點的哈弗曼編碼。
輔助方法
以下輔助結構體和方法會在壓縮和解壓縮過程中用到
struct node;
struct sortbyvalue
};void sethuffmanvalue(node* node,string s)
壓縮
壓縮檔案分五步:
1. 讀取原始檔並統計所有字元出現的次數
2. 將這些字元生成哈弗曼節點集合
3. 將哈弗曼集合生成哈弗曼樹
4. 對哈弗曼樹的每個節點生成哈夫曼編碼
5. 重新讀取原始檔,用每個字元對應的哈弗曼編碼替代該字元生成壓縮檔案
根據以上五步,實現壓縮的**為:
void huffmanpack(string path)
vector
wordvec;
map huffmanword;
auto mapbegin = wordmap.begin();
auto mapend = wordmap.end();
while (mapbegin != mapend)//生成哈弗曼節點集合以及根據字元和節點的字典
ofstream outfile("pack" + path, ios::binary);
short filesize = wordvec.size();
outfile.write((char*)&filesize, sizeof(short));//向壓縮檔案寫入字元種類的數量
sort(wordvec.begin(), wordvec.end(), sortbyvalue());
int temp = 0;
for (int i = 0; i//以字元出現數量的公升序向壓縮檔案寫入每個字元以及字元出現的次數
buff = wordvec[i]->value;
temp = wordvec[i]->sortvalue;
outfile.write(&buff, sizeof(buff));
outfile.write((char*)&temp, sizeof(int));
}int wordtag = wordvec.size()-1;
while (wordtag-->0)//通過每次挑選權值最小的兩個節點來生成哈夫曼樹
if (wordvec.size()>1)
sethuffmanvalue(wordvec[0], "");
else
//防止檔案中只有一種字元的情況
wordvec[0]->huffmanvalue = "1";
infile.close();
ifstream infilef(path, ios::binary);//再次開啟該檔案
infile.seekg(0, ios::beg);
streampos pos = infilef.tellg();
infilef.seekg(0, ios::end);
long
long filelength = infilef.tellg();
cout
<< "file length ="
<< filelength << endl;
infilef.seekg(pos);
outfile.write((char*)&filelength, sizeof(filelength));//寫入原始檔的總長度
char chartemp=0;
length = 8;
while (!infilef.eof())//將原始檔的每個字元的對應哈弗曼碼寫入壓縮檔案
else
if (length == 0)}}
if (length != 0)
infilef.close();
outfile.close();
}
解壓縮
解壓縮相當於壓縮過程的逆過程,需要四步實現解壓縮:
1. 讀取壓縮檔案中的所有字元及其在原始檔中的權值
2. 使用這些字元和權值生成哈弗曼節點集合
3. 將這些集合組成哈夫曼樹
4. 將壓縮檔案中的哈弗曼編碼用原始檔中對應字元代替生成解壓縮檔案
根據以上四步,可以實現解壓縮方法如下:
void huffmanrepack(string path)
int wordtag = wordvec.size() - 1;
while (wordtag-->0)
node* huffmantree = wordvec[0];
//sethuffmanvalue(wordvec[0], "");
ofstream outfile("repack" + path, ios::binary);
node* huffmantemp = huffmantree;
char tempbuff=0;
long
long filelength = 0;
infile.read((char*)&filelength, sizeof(filelength));//讀取原始檔的長度
while ((!infile.eof()) && (outfile.tellp()//將壓縮檔案中的哈弗曼編碼轉換為原始檔對應的字元存入檔案中
infile.read(&buff, sizeof(buff));
for (int i = sizeof(buff)*8-1; i >= 0; i--)
else
}
if (huffmantemp->left == nullptr)
buff << i;}}
infile.close();
outfile.close();
}
利用哈夫曼樹實現檔案壓縮和解壓縮
利用庫中的優先順序佇列實現哈夫曼樹,最後基於哈夫曼樹最終實現檔案壓縮。描述 1.統計檔案中字元出現的次數,利用優先順序佇列構建haffman樹,生成huffman編碼。構造過程可以使用priority queue輔助,每次pq.top 都可以取出權值 頻數 最小的節點。每取出兩個最小權值的節點,就n...
哈夫曼樹壓縮 解壓縮檔案
tips 注意二進位制讀寫檔案回車為 r n 詳細分析改天再填坑。還有單純形演算法 github include include include include include include include using namespace std template struct huffnode ...
哈夫曼編碼檔案壓縮解壓
哈夫曼編碼檔案壓縮解壓 沒整懂這份 竟然只能壓縮文字檔案,而且內容不能包含中文,不能解壓大於 8 k 的zip壓縮檔案 還有就是如果使用哈夫曼編碼壓縮的內容重複率不高,壓縮的效果不明顯,如果內容的重複率高壓縮的效果好點 呼叫封裝 public static byte hufmanzip byte b...