1. 程式人生 > >C++實現霍夫曼編碼檔案壓縮解壓

C++實現霍夫曼編碼檔案壓縮解壓

演算法設計與分析作業,程式碼如下:

#include <iostream>
#include <map>
#include <limits.h>
#include <iterator>
#include <string>
#include <fstream>
using namespace std;
typedef struct HTNode
{
    char ch;
    long freq;
    int parent,lchild,rchild;
}HTNode;

HTNode* HuffmanTree;

map
<char,long>
freqMap; map<char,string> codeMap; void Encode(HTNode* HTree,int pos,string str) { if(HTree[pos].lchild==-1 && HTree[pos].rchild==-1) codeMap[HTree[pos].ch]=str; if(HTree[pos].lchild!=-1) { str+='0'; Encode(HTree,HTree[pos].lchild,str); } str.erase(str.end()-1
); if(HTree[pos].rchild!=-1) { str+='1'; Encode(HTree,HTree[pos].rchild,str); } } /*Return the position of the two nodes of minimum frequency before pos*/ void selectMin2(HTNode* HTree,int pos,int& s1,int& s2) { int min1=INT_MAX,min2=INT_MAX; s1=s2=0; for
(int i=0;i<pos;i++) { if(HTree[i].parent!=-1) { continue; } else { if(HTree[i].freq<min2) { if(HTree[i].freq<min1) { min2=min1; s2=s1; min1=HTree[i].freq; s1=i; } else { min2=HTree[i].freq; s2=i; } } } } } int compressFile(char* inFileName,char* outFileName) { ifstream inFile(inFileName); ofstream outFile(outFileName,ios::binary); if(!inFile||!outFile) { cout<<"compressFile:Open file failed!"<<endl; return -1; } char ch; while(ch=inFile.get(),!inFile.eof()) { freqMap[ch]+=1; } int m=freqMap.size();//m is the number of leaf nodes in the Huffman tree int nodeNum=2*m-1; HuffmanTree=new HTNode[nodeNum];//There are (2m-1) nodes in total. map<char,long>::iterator it=freqMap.begin(); int i=0; while(it!=freqMap.end())//initialize leaf nodes { HuffmanTree[i].ch=it->first; HuffmanTree[i].freq=it->second; HuffmanTree[i].parent=HuffmanTree[i].lchild=HuffmanTree[i].rchild=-1; it++; i++; } for(int i=m;i<nodeNum;i++)//initialize other nodes { HuffmanTree[i].ch=NULL; HuffmanTree[i].freq=0; HuffmanTree[i].parent=HuffmanTree[i].lchild=HuffmanTree[i].rchild=-1; } for(int i=m;i<nodeNum;i++)//completing other nodes to construct the whole tree. { int s1,s2; selectMin2(HuffmanTree,i,s1,s2); HuffmanTree[i].freq=HuffmanTree[s1].freq+HuffmanTree[s2].freq; HuffmanTree[i].lchild=s1; HuffmanTree[i].rchild=s2; HuffmanTree[s1].parent=HuffmanTree[s2].parent=i; } string str; Encode(HuffmanTree,nodeNum-1,str); inFile.clear(); inFile.seekg(0,ios::beg); long length=0; map<char,string>::iterator it1=codeMap.begin(); for(it=freqMap.begin();it!=freqMap.end();it++,it1++) length+=it->second*it1->second.length(); outFile.write((char*)&length,sizeof(long));//length is the number of bit of the file outFile.write((char*)&nodeNum,sizeof(int)); outFile.write((char*)HuffmanTree,sizeof(HTNode)*nodeNum);//Write the whole tree to the file char buffer=0; int bit=8; while(ch=inFile.get(),!inFile.eof()) { //cout<<ch<<endl; str=codeMap[ch]; for(int i=0;i<str.length();i++) { buffer|=(str[i]-'0')<<(--bit);//Convert encoding from string to binary if(bit==0) { outFile.write(&buffer,1);//write to file every 8 bits buffer=0; bit=8; } } } delete []HuffmanTree; inFile.close(); outFile.close(); return 0; } int decompressFile(char* inFileName,char* outFileName) { ifstream inFile(inFileName,ios::binary); ofstream outFile(outFileName); if(!inFile||!outFile) { cout<<"decompressFile:Open file failed!"<<endl; return -1; } long length; int nodeNum; inFile.read((char*)&length,sizeof(long)); inFile.read((char*)&nodeNum,sizeof(int)); HTNode* HTree=new HTNode[nodeNum]; inFile.read((char*)HTree,sizeof(HTNode)*nodeNum); char ch; char buffer; char bit; int cursor=nodeNum-1; int byteNum=(int)length/8+1; for(int i=0;i<byteNum;i++) { inFile.read(&buffer,1); for(int j=7;j>=0;j--) { bit=(buffer>>j)&1; if(bit==0) cursor=HTree[cursor].lchild; else cursor=HTree[cursor].rchild; if(HTree[cursor].lchild==-1)//If we have search to leaf node,output the character and put the cursor at the position of root node { ch=HTree[cursor].ch; outFile<<ch; cursor=nodeNum-1; } } } delete []HTree; inFile.close(); outFile.close(); return 0; } int main() { cout<<"Compressing file..."<<endl; compressFile("graph.txt","graph_compress.dat"); cout<<"Decompressing file..."<<endl; decompressFile("graph_compress.dat","graph_de.txt"); return 0; }