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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章