C++實現霍夫曼編碼檔案壓縮解壓
阿新 • • 發佈:2019-01-05
演算法設計與分析作業,程式碼如下:
#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;
}