调试到了觉得实在不可能解决问题的地步了,还是选择了放弃。
哈夫曼编码,以及压缩及解压缩。
先建立哈夫曼树(静态链表)
struct node
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; }