`
westice
  • 浏览: 115560 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

最简单文件压缩程序huffman

阅读更多

   正在恶补数据结构,今天看到了二叉树,huffman编码,发现压缩程序很有意思,就按照huffman的编码思想实现了一个,没有经过算法改进,但是没有用第三方库,还能压缩一点空间,花了一天写完的。编码效率还是很菜。

 

只要调用compress  和decompress就可以压缩,解压,当然不是zip和rar,离他们还差十万八千里啊!

 

 

#include <iostream>

#define LEFT 0
#define RIGHT 1

using namespace std;

typedef struct huffmanTreetype{
    huffmanTreetype(){
       weight = 0;
       huffmancode = NULL;
       codelen = 0;
       list_next = NULL;
       list_prev = NULL;
       parent = NULL;
       left_child = NULL;
       right_child = NULL;   
       isleafnode = true;
       l_or_r = 2;
       frequency = 0;
    }    
    void printCode(){
       cout<<ch<<"  huffmancode:";
       for(int i = 0 ;i < codelen; i++){
           cout<<(int)huffmancode[i];
       }       
       cout<<endl;
    }    
    char *huffmancode;
    char codelen;
    char l_or_r;
    unsigned char ch;
    bool isleafnode;
    float weight;
    int frequency;
    struct huffmanTreetype *list_next,*list_prev,*parent,*left_child,*right_child;
    
}huffmanTree;    

huffmanTree *leaflist_header = NULL; //叶子节点头
huffmanTree *listtree_header = NULL; //huffman树 
int compress_len = 0;  //压缩后字节总长 
int compresscount = 0;
float compressprogress = 0; //压缩进度 

//加入链表末尾 
void appendList(huffmanTree *const header,huffmanTree *node){
    huffmanTree *iterator = header;
    while(iterator->list_next != NULL){
        iterator = iterator->list_next;
    }    
    iterator->list_next = node;
    node->list_prev = iterator;
    node->list_next = NULL;
}    

//断开链表中的元素,但不销毁
huffmanTree*  cutElement(huffmanTree *const header,huffmanTree *node){
    huffmanTree *iterator = header;
    huffmanTree *newheader = header;
    bool modify = false;
    while(iterator != NULL){
        if(iterator == node){
            modify = true;
            huffmanTree *node_prev = iterator->list_prev;
            huffmanTree *node_next = iterator->list_next;
            if(node_prev != NULL){
               node_prev->list_next = node_next;   
            }    
            if(node_next != NULL){
               node_next->list_prev = node_prev;   
            }    
            if(iterator == header){
               newheader = iterator->list_next;
               newheader->list_prev = NULL;
            }    
        }
        iterator = iterator->list_next;    
    }
    //把节点从链表中完全断开 
    if(modify){
        node->list_prev = NULL;
        node->list_next = NULL;    
    }        
    return newheader;
}    

//链表长度 
int listlength(huffmanTree *const header){
    huffmanTree *iterator = header;
    int len = 0;
    while(iterator != NULL){
        len++;
        iterator = iterator->list_next;
    }    
    return len;
}    

//打印链表 
void printlist(huffmanTree *const header){
    huffmanTree *iterator = header;
    while(iterator != NULL){
        cout<<"("<<iterator->ch<<" "<<iterator->weight<<")  ";
        iterator = iterator->list_next;
    }    
    cout<<endl;
}    

//先序取出叶子节点 
void preOrderTree(huffmanTree *rootnode){
   if(rootnode != NULL){
      if(rootnode->isleafnode){
          //cout<<rootnode->ch<<"  ";
         //如果为叶子节点,把它加入叶子链表中
          if(leaflist_header == NULL){
              leaflist_header = rootnode;
          }else{
              appendList(leaflist_header,rootnode);   
          }        
      }    
      preOrderTree(rootnode->left_child);
      preOrderTree(rootnode->right_child);   
   }    
}    

//设置huffman编码
void setfuffmanCode(huffmanTree *const listheader){
    huffmanTree *list_iterator = listheader;
    huffmanTree *tree_iterator = NULL;
    while(list_iterator != NULL){
        //左支为0,右支为1 
        tree_iterator = list_iterator;
        //首先要计算编码有多少位 
        while(tree_iterator->parent != NULL){
            list_iterator->codelen++;
            tree_iterator = tree_iterator->parent;
        }//tree while    
        //为code分配空间
        list_iterator->huffmancode = new char[list_iterator->codelen];
        tree_iterator = list_iterator;
        
        compress_len += (list_iterator->frequency * list_iterator->codelen);
        for(int i = list_iterator->codelen - 1;i >= 0 ;i--){
            list_iterator->huffmancode[i] = tree_iterator->l_or_r;
            tree_iterator = tree_iterator->parent;
        }        
        //list_iterator->printCode();
        
        list_iterator = list_iterator->list_next;
    } //list while   
    int leavetemp = compress_len%8;
    compress_len = compress_len/8;
    if(leavetemp != 0){
       compress_len ++;    
    }
}     

//选中剩下节点中两个最小的 
huffmanTree* findLasttwo(huffmanTree * header,huffmanTree **lasttwo){
    huffmanTree *iterator = header;
    lasttwo[0] = iterator;
    iterator = iterator->list_next;
   
    while(iterator != NULL){
        if(iterator->weight < lasttwo[0]->weight){
            lasttwo[0] = iterator;
        }    
        iterator = iterator->list_next;
    }    //end while
    //找倒数第二的 ,先解除最小的,最后加上最小的 
    header = cutElement(header,lasttwo[0]);
    iterator = header;
    lasttwo[1] = iterator;
    iterator = iterator->list_next;
     
    while(iterator != NULL){
        
        if(iterator->weight < lasttwo[1]->weight){  
             lasttwo[1] = iterator;
        }    
        
        iterator = iterator->list_next;
    }    //end while
    
    appendList(header,lasttwo[0]);
    return header;
}    

//根据统计数据创建huffman树 
void createHuffTree(int *statistics){
     //构造huffman树 
   int total_frequency = 0;
   for(int i = 0 ;i < 256 ;i++){
       total_frequency += statistics[i];
   }    
   for(int i = 0 ;i < 256 ;i++){
      if(statistics[i] != 0){ 
        //计算权值 
        huffmanTree *node = new huffmanTree;
        node->ch = i;
        node->frequency = statistics[i];     
        node->weight = statistics[i]/(float)total_frequency; 
        if(listtree_header == NULL){
            listtree_header = node;   
        }else{    
            appendList(listtree_header,node);
        }    
        //cout<<(char)i<<": weight  "<<node->weight<<endl;
      }    
   }    
   
   //直到链表中只有一个元素才停止构造树
   //选中剩下节点中两个权值非0最小的构造新节点 
   huffmanTree* lasttwo[2];
   //printlist(listtree_header);
   
   while(listlength(listtree_header) >= 2){//链表中至少有两个元素 
       listtree_header = findLasttwo(listtree_header,lasttwo);
       //cout<<"listlen:"<<listlength(list_header)<<endl;
       //cout<<"last two 0 :"<<lasttwo[0]->ch<<" 1:"<<lasttwo[1]->ch<<endl;
       //开始生成树结构 
       huffmanTree *node = new huffmanTree;
       lasttwo[0]->parent = node;
       lasttwo[0]->l_or_r = LEFT;
       lasttwo[1]->parent = node;
       lasttwo[1]->l_or_r = RIGHT;
       node->ch = '#';
       node->isleafnode = false;
       node->weight = lasttwo[0]->weight + lasttwo[1]->weight;
       node->left_child = lasttwo[0];
       node->right_child = lasttwo[1];
           
       //将链表重新链接好,可能把链表头都合并了 
       appendList(listtree_header,node);
       listtree_header = cutElement(listtree_header,lasttwo[0]);
       listtree_header = cutElement(listtree_header,lasttwo[1]);
       //printlist(listtree_header);
       
   }     
}    

int findCode(huffmanTree *const header,unsigned char src_byte,char **code){
    huffmanTree *iterator = header;
    while(iterator != NULL){
        if(iterator->ch == src_byte){
           *code = iterator->huffmancode;
           
           return iterator->codelen;
        }   
         iterator = iterator->list_next;
    }    
    return 0;
}    

#define setbit(x,y) x|=(1<<y) //将X的第Y位置1
#define getbit(x,y) (x&(1<<y))>>y        //读取x的第y位 
//由huffman压缩数据
void huffCompress(huffmanTree *const listheader,unsigned char *src,int src_len,unsigned char *dest,int dest_len){
    //扫描源数组,找到相应编码,写入位中
    //一次编码不够8bit记录下来,下次接着写 
    // 
    char *codeaddr;
    int destbitindex = 0;       //总bit索引 
    int destbyteindex = 0;      //byteindex由bitindex计算得来 
    for(int i = 0 ;i < src_len ;i++){
         compresscount++;
         compressprogress = compresscount/(float)src_len;
         
         if(compresscount%500000 == 0){
    
            cout<<"progress:"<<compressprogress * 100<<"%"<<endl;
            
         }    
         int codelen = findCode(listheader,src[i],&codeaddr);
         //先把上次遗留的bit位填满 
         int codebitscount = 0;
         //填写上次空位,从左边高位开始 
         for(int j = 0 ;j < codelen;j++){
             if(codeaddr[codebitscount++] == 1){
                 destbyteindex = destbitindex / 8;
                 int bitoffset = destbitindex % 8;  //离左边的偏移量 
                 setbit(dest[destbyteindex],7 - bitoffset);
                 
             }    
             destbitindex++;
         }    
    }    
}     

//传进huff树,源二进制串,目标串,目标串长度(此即解压后的长度) 
void huffDecompress(huffmanTree *const treeheader,unsigned char *binary_src,int src_len,unsigned char *dest,int dest_len){
    int bitindex = 0;
    int byteindex = 0;
    int destbyteindex = 0;
    huffmanTree *iterator = treeheader;
   // cout<<"数字:"; 
    //for(int i = 0 ;i < src_len;i++){
       //int a = binary_src[i];
       //char binbuf[32]; //存储二进制字串的空间
       //printf("%s", itoa(a, binbuf, 2)); //最后一个参数2表示2进制 
    //}   
    //cout<<endl<<"取数:";
    while(true){
       
       if(iterator->isleafnode){
           //查到了叶子节点 
           dest[destbyteindex] = iterator->ch;
           iterator = treeheader; //迭代器归位 
           destbyteindex++;
           if(destbyteindex == dest_len)break;    
       }    
       
       byteindex = bitindex / 8;
       int bitoffset = bitindex % 8; //离左边的偏移量 
       //读取源二进制串的一位,直到找到叶子节点 
       int srcbit = getbit(binary_src[byteindex],7 - bitoffset);
       //cout<<srcbit;
       if(srcbit == 0){
           iterator = iterator->left_child;  //左节点 
       }
       if(srcbit == 1){
           iterator = iterator->right_child;
       }        
       
       bitindex++; 
    }    
}     

//压缩文件
void compressFile(char *srcfilename){
    int srcfilenamelen = strlen(srcfilename);
    char compressname[srcfilenamelen + 15];
    compressname[0] = '\0';
    char suffix[] = ".huffman-YU";
    strcat(compressname,srcfilename);
    strcat(compressname,suffix);
    FILE *srcfile = fopen(srcfilename,"rb+");
    fseek(srcfile,0,SEEK_END);
    int file_len = ftell(srcfile);
    fseek(srcfile,0,SEEK_SET);
    unsigned char * filememory = new unsigned char[file_len];
    fread(filememory,1,file_len,srcfile);
    int statistics[256];
    for(int i = 0 ;i < 256 ;i++){
       statistics[i] = 0;
    }    
    for(int i = 0 ;i < file_len ;i++){
           statistics[filememory[i]]++;
    }    
    
     
    //用统计数据创建huffman树 
    createHuffTree(statistics);
         
    //给叶子节点编码 
    //先把叶子节点取出 
    preOrderTree(listtree_header);
    //cout<<endl<<"leaf:"<<endl;
    //cout<<"listlen:"<<listlength(leaflist_header); 
    //printlist(leaflist_header);
    //设置叶子节点的huffman编码 
    setfuffmanCode(leaflist_header);
    //根据huffman编码压缩数据 
    unsigned char * compress_dest = new unsigned char[compress_len];
    //清零
    for(int i = 0 ;i < compress_len;i++){
           compress_dest[i] = 0;
    }     
    
    huffCompress(leaflist_header,filememory,file_len,compress_dest,compress_len);
    cout<<"compress_len:"<<compress_len<<endl;
    //将压缩后的数据写入文件
    //先写文件名长度,文件名,256个统计数据
    FILE * compress_file = fopen(compressname,"wb+"); 
    fwrite(&srcfilenamelen,sizeof(int),1,compress_file);
    fwrite(srcfilename,sizeof(char),srcfilenamelen,compress_file);
    fwrite(statistics,sizeof(int),256,compress_file);
    //写入压缩数据长度和数据
    fwrite(&compress_len,sizeof(int),1,compress_file);
    fwrite(compress_dest,sizeof(char),compress_len,compress_file);
    
    fclose(srcfile); 
    fclose(compress_file);
    
}     

//解压文件
void decompressFile(char *srcfilename){
    cout<<endl<<"解压:"; 
    FILE *srcfile = fopen(srcfilename,"rb+"); 
    //读取文件名
    int filenamelen;
    fread(&filenamelen,sizeof(int),1,srcfile); 
    char *filename = new char[filenamelen + 1];
    fread(filename,sizeof(char),filenamelen,srcfile);
    filename[filenamelen] = '\0';
    //读取统计数据
    int statistics[256];
    int compressdatalen;
    fread(statistics,sizeof(int),256,srcfile);
    fread(&compressdatalen,sizeof(int),1,srcfile);
    unsigned char *compressdata = new unsigned char[compressdatalen];
    fread(compressdata,sizeof(char),compressdatalen,srcfile);
    int decompressdatalen = 0;
    for(int i = 0 ;i < 256; i++){
        decompressdatalen += statistics[i];
    }    
    cout<<"decompressdatalen: "<<decompressdatalen<<endl;
    createHuffTree(statistics); 
    //给叶子节点编码 
    //先把叶子节点取出 
    preOrderTree(listtree_header);
    //设置叶子节点的huffman编码 
    setfuffmanCode(leaflist_header);
    //解压
    unsigned char *decompressdata = new unsigned char[decompressdatalen];
    huffDecompress(listtree_header,compressdata,compressdatalen,decompressdata,decompressdatalen); 
    char attachchars[] = "copy-";
    char copyfilename[100];
    copyfilename[0] = '\0';
    strcat(copyfilename,attachchars);
    strcat(copyfilename,filename);
    cout<<"copyname:"<<copyfilename<<endl;
    FILE *destfile = fopen(copyfilename,"wb+");
    fseek(destfile,0,SEEK_SET);
    fwrite(decompressdata,sizeof(char),decompressdatalen,destfile);
    fclose(srcfile);
    fclose(destfile);
}     

main(){

   //compressFile("iphone.pdf");
   decompressFile("iphone.pdf.huffman-YU");
   
   system("PAUSE");
}    





分享到:
评论
1 楼 javafound 2010-11-21  

相关推荐

    用于文件压缩的huffman算法.zip_huff 压缩_huffman_vc huffman 压缩_压缩算法_文件压缩

    在本压缩包中,"用于文件压缩的huffman算法"可能是包含具体实现细节的文档,如源代码、算法描述或步骤详解。"www.pudn.com.txt"可能是一个示例文本文件,用于演示哈夫曼压缩的效果。开发者使用VC++(Visual C++)这...

    文本文件压缩【huffman编码实现】

    文本文件压缩是信息处理中的一个重要领域,特别是在大数据和存储有限的场景下,高效的数据压缩技术显得尤为关键。Huffman编码是一种基于频率的无损数据压缩方法,由David A. Huffman在1952年提出,它是数据结构课程...

    Huffman 压缩

    简单的利用Huffman算法 实现的压缩程序。 压缩效率不是很高,但是实现了最基本的压缩

    huffman编码的压缩与解压缩

    在C#中,Visual Studio(VS)提供了强大的开发环境和丰富的库支持,使得实现这样的压缩和解压缩程序变得相对简单。开发者可以利用IO类库处理文件读写,利用位操作类库处理二进制数据,以及利用调试工具测试和优化...

    Huffman编码的c和matlab实现

    本文旨在通过具体的实验,让读者深入了解和掌握Huffman编码算法及其在文件压缩和还原中的应用。实验的目标是熟练运用Huffman编码算法对文件进行高效压缩,并在标准测试文集上评估其压缩效果。此外,还需设计简单的...

    文件压缩解压程序(qt5.5版本可用)

    本项目涉及的是一个基于Qt5.5版本的文件压缩解压程序,该程序带有用户界面和交互按钮,方便用户操作。值得注意的是,开发者在开发过程中遇到了不同Qt版本之间压缩库DLL不兼容的问题,这表明不同版本的Qt框架可能对库...

    Huffman测试文件.zip

    这个“Huffman测试文件.zip”压缩包包含的是一套用于测试和生成哈弗曼编码的系统,适合进行程序设计和算法的综合训练。在这个训练中,用户可以处理"data"类型和"txt"类型的文件,这些文件内容可以通过简单的文本编辑...

    实验2 Huffman编码对英文文本的压缩和解压缩.docx

    通过使用VC++ 6.0开发环境,学生需要编写程序实现英文文本的压缩和解压缩功能,并且设计一个简单的用户界面。在这一过程中,他们需要运用到C语言编程,特别是位运算和文件操作,同时还需要理解数据结构,如链表、...

    huffman编码程序

    哈夫曼编码的主要目标是为每个字符或符号分配一个唯一的二进制码,使得最频繁出现的字符拥有最短的编码,以此来提高压缩效率。 在描述中提到的“在文本指定的本中写一段小写的代码,然后运行”,这可能是要求你实现...

    Huffman编码

    在数据压缩领域,Huffman编码是基础且重要的技术,尤其在文本文件压缩中广泛应用。 在C++中实现Huffman编码,首先需要计算输入文件中每个字符的出现频率。这可以通过遍历文件并统计每个字符的出现次数来完成。接着...

    huffman编解码C实现

    哈夫曼编码(Huffman ...哈夫曼编码虽然简单,但它的思想广泛应用于数据压缩领域,例如在图像、音频和文本文件的压缩标准中都有所体现。了解并能实现哈夫曼编码对于学习数据压缩和信息理论是非常基础且重要的一步。

    JPEG图片压缩程序(1/5)

    项目:JPEG图片压缩程序(1/5) 作者:zyl910 E-Mail:zyl910@sina.com 说明: 由于JPEG图片压缩的复杂性。就算是是最简单的基线系统(BaseLine), 若想一次实现对算法要求太高,且不易理解,再加上我对它不是...

    MFCHuffmanZip

    MFCHuffmanZip是一个基于Microsoft Foundation Class (MFC)库,并运用Huffman编码实现的文件压缩程序。MFC是微软提供的一套C++类库,它为Windows应用程序开发提供了丰富的功能和接口,使得开发者可以更容易地构建...

    JPEG图片压缩程序 v2.0

    使用的是最简单的基线系统(BaseLine)压缩方式, 量化表及Huffman表都是与ACDSee一致的,没有提供自适应Huffman表压缩功能。 速度测试 ~~~~~~~~ CPU:赛杨733 内存:128MB SDRAM 操作系统:Windows 98 SE...

    压缩与解压缩算法及示例程序

    本文将深入探讨压缩与解压缩算法,特别是哈夫曼编码这一经典压缩方法,并提供一个简单的实现示例。 哈夫曼编码是一种高效的数据压缩算法,它基于字符出现频率进行编码。在文本文件中,某些字符(如空格、e、t等)...

    java实现哈夫曼压缩与解压缩的方法

    哈夫曼压缩是一种高效的压缩算法,广泛应用于文件压缩、数据压缩、图像压缩等领域。Java语言是实现哈夫曼压缩的不二之选,本文将详细介绍Java实现哈夫曼压缩与解压缩的方法。 哈夫曼树 哈夫曼树是一种特殊的二叉树...

    ZIP压缩工具源码

    2. **压缩算法实现**:DEFLATE算法是ZIP文件的标准,它结合了LZ77(一种滑动窗口压缩)和Huffman编码。E语言中实现这个算法需要理解这两个部分的原理,创建相应的数据结构和函数来执行压缩和解压缩操作。 3. **文件...

    无损压缩算法源代码包

    `compress` 是一个早期的无损文件压缩程序,基于LZW(Lempel-Ziv-Welch)算法的简化版本。LZW是一种字典编码方法,通过查找重复的模式并用短码代替来减少数据量。`compress` 在处理文本文件时表现出色,但在处理...

    易语言win8压缩解压源码

    在开发压缩解压程序时,这些基本操作必不可少,因为它们涉及到对原始文件的读取和生成压缩/解压缩后文件的写入。 三、压缩算法 压缩技术主要基于不同的压缩算法,常见的有LZ77、LZ78、Huffman编码、DEFLATE(gzip和...

    文件处理.WinZip.Pro.15.5.Build.9579.压缩解压简体中文烈火破解版(验证版).zip

    WinZip Pro是一款广泛使用的文件压缩和解压缩软件,由WinZip Computing公司开发。15.5 Build 9579是该系列的一个重要版本,它提供了丰富的功能,包括支持多种压缩格式、文件加密、集成到Windows资源管理器中等。该...

Global site tag (gtag.js) - Google Analytics