zoukankan      html  css  js  c++  java
  • Huffman编码实现文件的压缩与解压缩。

    以前没事的时候写的,c++写的,原理很简单,代码如下:

      1 #include <cstdio>
      2 #include <cstdlib>
      3 #include <iostream>
      4 #include <string>
      5 //#include <bitset>
      6 #include <fstream>
      7 #include <ctime>
      8 
      9 const int maxCodeNum = 256;
     10 
     11 using namespace std;
     12 
     13 //哈夫曼树的树节点
     14 struct HaffTreeNode{
     15     HaffTreeNode * lNode;
     16     HaffTreeNode * rNode;
     17     string  haffCode;
     18     int value;
     19     int alpha;
     20     HaffTreeNode()
     21         :lNode(NULL), rNode(NULL), haffCode(""), value(0), alpha(0){;}
     22 };
     23 
     24 //链表节点,用于生成哈夫曼树
     25 struct ListNode{
     26     struct HaffTreeNode HaffTreeNode;
     27     ListNode *nextListNode;
     28     ListNode()
     29         :nextListNode(NULL){;}
     30 };
     31 
     32 //用与保存输入文件统计信息的hash表
     33 typedef struct HashTable{
     34     int value;
     35     int alpha;
     36     HashTable()
     37         :value(0), alpha(0){}
     38     //比较函数用于排序使用
     39     inline friend int operator-(const HashTable & a, const HashTable & b){
     40         return a.value - b.value;
     41     }
     42 } HashTable;
     43 HashTable charHashTable[maxCodeNum];
     44 
     45 
     46 //排序使用的比较大小的函数
     47 int hashComp(const void * a, const void * b)
     48 {
     49     return  *((HashTable *)a) - *((HashTable *)b);
     50 }
     51 
     52 
     53 //创建一个哈夫曼树
     54 HaffTreeNode * createHaffTreeNodeTree(HashTable table[])
     55 {
     56     ListNode *root = new ListNode;
     57     ListNode *next = root;
     58     for(int i = 0; /*i < maxCodeNum - 1*/; ++i){
     59         if(table[i].value == 0)//如果对应的码不为0,就为其分配一个树节点
     60             continue;
     61         next->HaffTreeNode.alpha = table[i].alpha;
     62         next->HaffTreeNode.value = table[i].value;
     63         if(i ==maxCodeNum - 1)
     64             break;
     65         next->nextListNode = new ListNode;
     66         next = next->nextListNode;
     67     }
     68 
     69     while(root->nextListNode != NULL){
     70         ListNode * currNode = new ListNode;
     71         currNode->HaffTreeNode.value = root->HaffTreeNode.value + root->nextListNode->HaffTreeNode.value;
     72         currNode->HaffTreeNode.lNode =  &(root->HaffTreeNode);
     73         currNode->HaffTreeNode.rNode =  &(root->nextListNode->HaffTreeNode);
     74         root = root->nextListNode->nextListNode;    //概率最小的两个码相加组成一个新的节点
     75 
     76         ListNode * nextNode = root;
     77         ListNode * prevNode = NULL;
     78         while(nextNode != NULL && currNode->HaffTreeNode.value > nextNode->HaffTreeNode.value){
     79             prevNode = nextNode;
     80             nextNode = nextNode->nextListNode;
     81         }
     82 
     83         if(prevNode == NULL){//将这个新的节点插入到所有节点之前(currNode目前还是最小的)
     84             currNode->nextListNode = nextNode;
     85             root = currNode;
     86         }else{//插入到节点中间或者节点之后的位置
     87             prevNode->nextListNode = currNode;
     88             currNode->nextListNode = nextNode;
     89         }
     90     }//在这个list中所有的元素遍历完成之后返回
     91     return &(root->HaffTreeNode);//返回书的根节点的哈弗满节点,这个节点已经构造成为了一棵树
     92 }
     93 
     94 string huffmanCodeTable[maxCodeNum];
     95 string haffCode;
     96 
     97 //给哈夫曼树编码
     98 void createHaffmanTable(HaffTreeNode * root)
     99 {
    100     if(root->lNode == NULL && root->rNode == NULL){
    101         huffmanCodeTable[root->alpha] = haffCode;
    102         haffCode.erase(haffCode.length() - 1);
    103         return;
    104     }//给各个节点赋予相应的哈夫曼编码
    105     haffCode.append("0");
    106     createHaffmanTable(root->lNode);
    107 
    108     haffCode.append("1");
    109     createHaffmanTable(root->rNode);
    110 
    111     if(!haffCode.empty()){
    112         haffCode.erase(haffCode.length() - 1);
    113     }
    114     return;
    115 }
    116 
    117 //将生成的二进制长串编码转换成字符用于存储在压缩文件中
    118 unsigned char StrToBin(string str)
    119 {
    120     unsigned int ans =0;
    121     int tmpNum = atoi(str.c_str());
    122     int multiNum = 1;
    123     while(tmpNum != 0){
    124         ans += tmpNum%10*multiNum;
    125         tmpNum/=10;
    126         multiNum *= 2;
    127     }
    128     return (unsigned char) ans;
    129 }
    130 
    131 //用于将压缩文件的字符转换成huffman编码
    132 string BinToStr(unsigned char c)
    133 {
    134     string tmpNumStr;
    135     while(c != 0){
    136         tmpNumStr.insert(tmpNumStr.begin(), (unsigned char)(c%2 + '0'));
    137         c /= 2;
    138     }
    139     if(tmpNumStr.length() < 8){
    140         tmpNumStr.insert(tmpNumStr.begin(),  8 - tmpNumStr.length(), '0');
    141     }
    142     return tmpNumStr;
    143 }
    144 
    145 //下面是将huffman码译成原字符的程序
    146 char huffDecode(HaffTreeNode * root, string & code)
    147 {
    148     unsigned int i;
    149     for( i = 0; i < code.length(); ++i){
    150         if(root->alpha == 0)
    151             root = (code[i] - '0')?root->rNode:root->lNode;
    152         else{
    153             code.erase(0, i);
    154             return root->alpha;
    155         }
    156     }
    157     if(root->alpha !=0){
    158         code.erase(0, i);
    159         return root->alpha;
    160     }
    161     code.clear();
    162     return '';
    163 }
    164 
    165 
    166 
    167 int main(int argc, char ** argv)
    168 {
    169     if(argc != 3){
    170         printf("Error number of arguments!
    ");
    171     }
    172     FILE * fin = fopen(argv[1], "r");
    173     int c = 0;
    174     while((c = fgetc(fin)) != EOF && c != '
    '){
    175         putchar(c);
    176         putchar('*');
    177         charHashTable[c].alpha = c;
    178         charHashTable[c].value++;
    179     }
    180 
    181     qsort(charHashTable, sizeof(charHashTable)/sizeof(charHashTable[0]),
    182             sizeof(charHashTable[0]), hashComp);
    183     /*建立有关本文件的huffman树*/
    184     HaffTreeNode * haffTreeRoot = createHaffTreeNodeTree(charHashTable);
    185     createHaffmanTable(haffTreeRoot);
    186 
    187     cout << "Char	Times	Codes";
    188     for(int i = 0; i < maxCodeNum; ++i){
    189         if(charHashTable[i].value != 0){
    190             cout << (char)charHashTable[i].alpha << "	" << charHashTable[i].value
    191                  << "	" << huffmanCodeTable[charHashTable[i].alpha] << "
    ";
    192         }
    193     }
    194 
    195     FILE * fout;
    196     if((fout = fopen(argv[2], "w")) == NULL){
    197         perror("open output file error!
    ");
    198     }
    199     rewind(fin);
    200     string buf; 
    201 
    202     while((c = fgetc(fin)) != EOF){ /*将文件通过huffman码转来进行压缩*/
    203         //printf("The char is %c  ", c);
    204         buf += huffmanCodeTable[c];
    205         cout << buf << endl;
    206         if(buf.length() > 8){   //当转换的字符得到的huffman码达到8的时候转换成一个字符填入目标文件
    207             fputc(StrToBin(buf.substr(0, 8)), fout);
    208             buf.erase(0, 8);
    209         }
    210     }
    211 
    212     int leftZero = 0;   //保存不到8位的余留位的个数
    213     if(!buf.empty()){
    214         buf.append((leftZero = 8 - buf.length()), '0');
    215         fputc(StrToBin(buf), fout);
    216     }
    217 
    218     if(fclose(fin) == -1)
    219         perror("close file error!
    ");
    220     if(fclose(fout) == -1)
    221         perror("close file error!
    ");
    222 
    223     if((fin = fopen(argv[2], "rb")) == NULL)//打开压缩文件,开始解码
    224         perror("Open file error!
    ");
    225     if((fout = fopen("huffmanDecompose.txt", "w")) == NULL)
    226         perror("Open file error!
    ");
    227 
    228     //开始解码
    229     int bin;
    230     buf.clear();
    231     while((bin = fgetc(fin)) != EOF){
    232         buf.append(BinToStr(bin));
    233     }
    234 
    235     while(buf.length() - leftZero != 0 && !buf.empty()){
    236         fputc(huffDecode(haffTreeRoot, buf), fout);
    237     }
    238     if(fclose(fin) != 0)
    239         perror("close file error!
    ");
    240     if(fclose(fout) != 0)
    241         perror("close file error!
    ");
    242     return 0;
    243 }

    ./a.out file1 file2
    file1:输入文件
    file2:输出文件(压缩后)
    要锁完成后会将文压缩文件解压到huffmanDecompose.txt这个文件中

  • 相关阅读:
    MYSQL5.6学习——mysqldump备份与恢复
    【转】分布式与集群的区别
    (四)伪分布式下jdk1.6+Hadoop1.2.1+HBase0.94+Eclipse下运行wordCount例子
    (三)配置Hadoop1.2.1+eclipse(Juno版)开发环境,并运行WordCount程序
    git pull总是要输入账号和密码
    Undefined index: validate(thinkphp)
    mysql table status
    如何学习web开发环境搭建和脚手架
    serversql tinkphp
    apache 配置
  • 原文地址:https://www.cnblogs.com/-wang-cheng/p/4928089.html
Copyright © 2011-2022 走看看