一个失败的哈夫曼压缩解压缩代码

调试到了觉得实在不可能解决问题的地步了,还是选择了放弃。

哈夫曼编码,以及压缩及解压缩。

先建立哈夫曼树(静态链表)

struct node
{
    char val ;
    int frequent ;
    short parent ;
    short lChild ;
    short rChild ;
} ;

node HuffmanSpace[2*N-1] ;

N我取的128,256也没什么,对于压缩英文字符,128够了。

然后就是统计词频。有一个6M的英文文件,然后get挨个读取,什么字符,包括换行,回车,空格等都是读进来了的。

用HuffmanSpace[(int)tmp].frequent++记录,读完,算是完成了初始化 ; 

然后就是建立哈夫曼树,每次从parent=-1的节点中找出频率最小的两个节点,然后HuffmanSpace[pos++].frequent等于这两个节点的频率之和,然后左右子树等于两个节点数组位置。两个节点的parent指向新节点。

这样HuffmanSpace[2*N-2]就是树的最顶层。

然后就是获取哈夫曼编码。同样采取叶子到根逆序建立。

strcut HuffmanCode

{

char val ; 

char bits[N] ; 

} ; 

N有点多了,也没太刻意计算。由于HuffmanSpace[]前N个都是叶子节点,这样就可以一个for循环搞定。

for循环内部每次都不断上溯,直到遇到根节点。这样编码也做好了。

接下来就是压缩。

打开一个文件,同样依次get进来。创建一个buffer的string,buffer+=huffmanCode[(int)tmp].bits ; 

读完后就要重新编码输出到文件。重新编码,最开始我用的int,每次从buffer中读取32位,转换为int,然后write到文件。循环直到buffer为空。后面buffer肯定不是整的32位了,要末位补“0”。

最后就是解压缩。

噩梦就此开始。

原理和压缩差不多,read读进来,把int转换为32位二进制字符,append到buffer上,读完然后按buffer查找哈夫曼树,读出对应的字符。

然而问题是:每次read都会提前终止!!根本读不完文件就会终止。

然后我就开始了有史以来最蛋疼的调试。加输出,看字符串状态,然后确定Encording的字符串肯定是对的,因为如果根据刚产生的string不重新编码直接Decording结果很完美。可是经过这重新编码和重新读码,就只能解出前面一部分了。所以,可以确定是read函数提前终止了,没有到文件末尾。然后我又尝试了put,get取代write和read,还是会提前终止,然后,我就知道,这个,没法弄了。

还是把代码贴上,main函数随便写的。


#ifndef HUFFMAN_H_INCLUDED
#define HUFFMAN_H_INCLUDED
#include <fstream>
#include <iostream>
#include <cstring>
#include <string>
#define N 128

using namespace std ;

struct node
{
    char val ;
    int frequent ;
    short parent ;
    short lChild ;
    short rChild ;
} ;
node HuffmanSpace[2*N-1] ;
typedef int Huffman,position ;

void init(node HuffmanSpace[],int len)
{
    for(int i = 0 ; i < len ; i++)
    {
        if(i < N)
            HuffmanSpace[i].val = i ;
        HuffmanSpace[i].frequent = 0 ;
        HuffmanSpace[i].parent = -1 ;
        HuffmanSpace[i].lChild = -1 ;
        HuffmanSpace[i].rChild = -1 ;
    }
}
void getFrequent(node HuffmanSpace[])
{
    fstream file("big.txt") ;
    if(file == NULL)
    {
        cout <<"\n文件打开失败\n" ;
        return ;
    }
    while(!file.eof())
    {
        char tmp ;
        tmp = file.get() ;
        if(tmp>=0 && tmp < N)
            HuffmanSpace[(int)tmp].frequent ++ ;
    }
    file.close() ;
}
void getMinNode(node HuffmanSpace[],int len,position & smaller,position & bigger)
{
    for(int i = 0 ; i < len ; i++)
    {
        if(HuffmanSpace[i].parent == -1)
        {
            smaller = i ;
            break ;
        }

    }
    for(int i = smaller ; i < len ; i++)
    {
        if(HuffmanSpace[i].parent == -1)
        {
            if(HuffmanSpace[smaller].frequent>HuffmanSpace[i].frequent)
                smaller = i ;
        }

    }
    for(int i = 0 ; i < len ; i++)
    {
        if(HuffmanSpace[i].parent == -1 && smaller!= i)
        {
            bigger = i ;
            break ;
        }
    }
    for(int i = bigger ; i < len ; i++)
    {
        if(HuffmanSpace[i].parent == -1 && smaller!= i)
        {
            if(HuffmanSpace[bigger].frequent > HuffmanSpace[i].frequent)
                bigger = i ;
        }
    }
}
void CreateHuffmanTree(Huffman & HT,node HuffmanSpace[])
{
    position pos = N ;
    position smaller,bigger ;
    while(pos < 2*N - 1)
    {
        getMinNode(HuffmanSpace,pos,smaller,bigger) ;
        HuffmanSpace[pos].frequent = HuffmanSpace[smaller].frequent+HuffmanSpace[bigger].frequent ;
        HuffmanSpace[pos].lChild = smaller ;
        HuffmanSpace[pos].rChild = bigger ;
        HuffmanSpace[smaller].parent = pos ;
        HuffmanSpace[bigger].parent = pos ;
        pos++ ;
    }
    HT = 2*N -2 ;

}
struct HuffmanCode
{
    char val ;
    char bits[N+1] ;
} ;
HuffmanCode huffmanCode[N] ;
void init(HuffmanCode huffmanCode[],int len)
{
    for(int i = 0 ; i < len ; i++)
    {
        huffmanCode[i].val = -1 ;
        strcpy(huffmanCode[i].bits,"") ;
    }
}

void CharSetHuffmanEncording(node HuffmanSpace[] , HuffmanCode huffmanCode[] )
{
    char tmp[N] ;
    for(int i = 0 ; i < N ; i++)
    {
        huffmanCode[i].val = HuffmanSpace[i].val ;
        position parent ;
        int pos = 0 ;
        int copy = i ;
        while((parent = HuffmanSpace[copy].parent) != -1)
        {
            tmp[pos++] = (HuffmanSpace[parent].lChild == copy)?'0':'1' ;
            copy = parent ;
        }
        tmp[pos] = '\0' ;
        for(int k = 0 ; k < pos ; k++)
        {
            huffmanCode[i].bits[k] = tmp[pos-1-k] ;
        }
        huffmanCode[i].bits[pos] = '\0' ;
    }
}
void saveCharSet(HuffmanCode huffmanCode[])
{
    ofstream hc("HuffmanCode.txt") ;
    if(hc == NULL)
    {
        cout <<"File open failed !\n" ;
        return ;
    }
    for(int i = 0 ; i < N ; i++)
    {
        hc << huffmanCode[i].val ;
        hc <<" " ;
        hc << huffmanCode[i].bits ;
        hc <<" " ;
    }
    hc.close() ;
    cout <<"HuffmanCode has been saved ! \n" ;
}
unsigned char binaryToDecimal(string & buffer)
{
    unsigned char d = 0 ;
    int length = sizeof(char)*8 ;
    for(int i = 0 ; i < length ; i++)
    {
        d+=(buffer.at(i)-'0')*(1 << length -i - 1) ;
    }
    buffer.erase(0,length) ;
    return d ;
}
int Encording(HuffmanCode huffmanCode[],fstream & in)
{
    const int BUFFER_SIZE = 100000 ;
    string buffer  = "" ;
    int lowTimes = BUFFER_SIZE/30 ;
    int tmp ;
    int counter = 0 ;
    ofstream out("afterEncording.txt",ios::app) ;
    if(out == NULL)
    {
        cout <<"创建文件失败 \n" ;
        return -1;
    }
    while((tmp = in.get())!=EOF)
    {
        buffer+=huffmanCode[tmp].bits ;
        counter++ ;
        if(counter>lowTimes)
        {
            while(buffer.length()>sizeof(char)*8+1)
            {
                //重新编码
                unsigned char d = binaryToDecimal(buffer) ;

                out.write((char *)&d,sizeof(char)) ;
            }
            counter = 0 ;
        }
    }
    //文件读取完毕,buffer中还有字符未处理
    while(buffer.length()>sizeof(int)*8)
    {
        unsigned char d = binaryToDecimal(buffer) ;
        out.write((char *)&d,sizeof(char)) ;
    }
    int remainLength = buffer.length() ;
    for(int i = buffer.length() ; i < sizeof(char)*8+1 ; i++)
    {
        buffer+="0" ;
    }
    unsigned char d = binaryToDecimal(buffer) ;
    out.put(d) ;
    out.put(EOF) ;
    in.close() ;
    out.close() ;

    return remainLength ;
}
void decimalToBinary(unsigned char d,char bits[sizeof(char)*8+1])
{
    for(int i = 0 ; i< sizeof(char)*8 ; i++)
        bits[i] = '0' ;
        bits[sizeof(char)*8] = '\0' ;
    int counter = sizeof(char)*8 - 1 ;
    while(d!= 0&&counter >= 0)
    {
        bits[counter--] = (d%2 +'0') ;
        d/=2 ;
    }
}
char singleDecording(node HuffmanSpace[],Huffman HT,string & buffer)
{
    position pos = HT ;
    int counter = 0 ;
    while(counter<buffer.length())
    {
        if(HuffmanSpace[pos].lChild == -1 && HuffmanSpace[pos].rChild == -1)
        {
            buffer.erase(0,counter) ;
            return HuffmanSpace[pos].val ;
        }
        if(buffer.at(counter) == '0')
            pos = HuffmanSpace[pos].lChild ;
        else
            pos = HuffmanSpace[pos].rChild ;
        counter ++ ;
    }
    buffer.erase(0,counter) ;
    return -1 ;
}
void Decording(node HuffmanSpace[],Huffman HT,fstream & in,int remainLength)
{
    const int BUFFER_SIZE = 100000 ;
    int lowTimes = BUFFER_SIZE/(sizeof(char)*8) ;
    char bits[sizeof(char)*8+1] ;
    string buffer="" ;
    unsigned char tmp ;
    ofstream out("Decording.txt",ios::app) ;
    if(out == NULL)
    {
        cout <<"File open failed!\n" ;
        return ;
    }
    int counter = 0 ;
    while(true)
    {
  in.read((char *)&tmp,sizeof(char)) ;

        if(in.eof())
        {
            cout <<"文件结束\n" ;
            break ;
        }
        decimalToBinary(tmp,bits) ;
        buffer+=bits ;
        counter++ ;
        if(counter> lowTimes)
        {
            cout <<"Error" ;
            return ;
            while(buffer.length()>remainLength)
            {
                char x = singleDecording(HuffmanSpace,HT,buffer) ;
                cout <<x ;
                out.put(x) ;
            }
        }
    }
    //
    while(buffer.length()>remainLength)
            {
                char x = singleDecording(HuffmanSpace,HT,buffer) ;
                cout <<x ;
                out.put(x) ;
            }
    in.close() ;
    out.close() ;
}



#endif // HUFFMAN_H_INCLUDED





#include "Huffman.h"


using namespace std;


int main()
{
    init(HuffmanSpace,2*N-1) ;
    getFrequent(HuffmanSpace) ;
    Huffman HT ;
    CreateHuffmanTree(HT,HuffmanSpace) ;
    init(huffmanCode,N) ;
    CharSetHuffmanEncording(HuffmanSpace,huffmanCode) ;
    fstream in("11.jpg") ;
    if(in == NULL)
    {
        cout <<"文件打开失败\n" ;
        return 0 ;
    }


    int remainLength=Encording(huffmanCode,in) ;
    fstream decord("afterEncording.txt") ;
    if(decord == NULL)
    {
        cout <<"文件打开失败\n" ;
        return 0 ;
    }
    Decording(HuffmanSpace,HT,decord,3) ;
    return 0;
}


你可能感兴趣的:(一个失败的哈夫曼压缩解压缩代码)