zoukankan      html  css  js  c++  java
  • 用C++实现文件压缩(1 哈弗曼编码)

    今天下午想把文件压缩写一下,因为我觉得这个还是比较锻炼技术的,对数据结构的要求应该比较高,权当练习了吧。

    我采用的压缩方式是Huffman编码,不过比较囧的是,我拼写拼错了,我拼的是haffman,在后面的代码也是出尽洋相。

    huffman是非常经典的一种编码形式,不过现在好像用的不多了,但是这种压缩编码的好处在于数据是无损压缩的,而且非常经典。

    在构造huffman树,要做的步骤如下:

    1 对文件的元素进行统计,其实就是个计数,我这里的元素是以字节为单位的,毕竟任何文件都可以转化为字节流的形式,处理起来方便的很。

    2 然后对统计结果进行一次由小到大的排序,排序的key值就是元素出现的次数。

    3 接着取出来排好序的数组的前两个元素,求和,并且再其左右子树上创建这两个元素的副本,然后再扔回首部,此时扔回数组中的,就是包含子树的节点了。在这里有个代码优化的小技巧,能在一定程度上提高效率,减少不必要的操作。

    4 此时原来已经排好序的数组可能会遭到破坏,必须重新进行排序,因为数组大体是有序的,所以使用此时效率最高的一步插入排序,时间复杂度仅为O(n),我专门写了个函数来实现这个功能,并且进行了简单的测试。

    5 然后再取出首部的前两个元素,重复上面步骤3,直到数组中的元素个数为1.

    最终数组中仅存的元素,就是一棵二叉树的Root。

    这样huffman树的构造就完成了。

    在huffman树构造完成后,接着要做的就是根据huffman树获取其huffman编码,这个还是很简单的,就是使用递归,左树传入0,右树传入1,依次递归下去,遇到叶子节点就直接输出,当然了,如果需要添加到某个数据结构中,只要在递归函数中给个参数接口,或者设置一个全局的容器,都能解决,换言之,类似于输出重定向。

    这样上面的步骤完成后,就能很好的获取到huffman编码了。不过根据huffman编码结果将字符型的0,1写入到二进制中的0,1还有一些比较关键的函数需要处理,还没想到比较好的点子,不过最基础的蛮力方法肯定是能写的,但是,效率就不好说了。

    另外获取huffman编码中,用于0,1传递的参数肯定是要用一个buffer的,这个buffer我用的是char字符串,现在有个问题就是,这个字符串的长度只要大于多少就能满足任何2GB以下文件的huffman编码呢?

    我觉得这个题可以用来出一道笔试面试题,好好想一想就能想明白的。我的结果是 254,你觉得呢?

    最近笔试面试写了不少题,都是被人考,现在我来考考别人~

    另外huffman的解码我也基本想到思路了,明天有时间的话就试着明天实现。

    程序运行结果:

    第一列是字符的数值,第二列是出现的次数,第三列是其huffman编码。

    我这代码放眼望去,尽是被拼成了haffman的错误拼写……

    程序代码:

      1 #include <iostream>
      2 #include <windows.h>
      3 #include <vector>
      4 #include <algorithm>
      5 using namespace std;
      6 
      7 struct HaffmanStruct
      8 {
      9     //a small structure
     10     HaffmanStruct():val(0),ncounts(0),lNext(NULL),rNext(NULL){}
     11     bool operator < (HaffmanStruct &);
     12     bool operator > (HaffmanStruct &);
     13     void Reset();
     14     unsigned char val;
     15     unsigned int ncounts;
     16     //used for tree
     17     HaffmanStruct * lNext;
     18     HaffmanStruct * rNext;
     19 };
     20 
     21 bool HaffmanStruct::operator > (HaffmanStruct & hs)
     22 {
     23     return ncounts > hs.ncounts;
     24 }
     25 
     26 bool HaffmanStruct::operator < (HaffmanStruct & hs)
     27 {
     28     return hs.ncounts > ncounts;
     29 }
     30 
     31 void HaffmanStruct::Reset()
     32 {
     33     val = 0;
     34     ncounts = 0;
     35     lNext = NULL;
     36     rNext = NULL;
     37 }
     38 
     39 /*
     40 Created in 2013 10 03
     41 ergodic the Haffman tree
     42 */
     43 template <class T>
     44 void ErgodicTree(T & Root, char * szStr, int nDeep)
     45 {
     46     if(Root.lNext == NULL && Root.rNext == NULL)
     47         cout << (int)Root.val << ends << Root.ncounts 
     48         << ends <<szStr << endl;
     49     szStr[nDeep] = '0';
     50     if(Root.lNext != NULL)
     51         ErgodicTree(*Root.lNext, szStr, nDeep + 1);
     52     szStr[nDeep] = '1';
     53     if(Root.rNext != NULL)
     54         ErgodicTree(*Root.rNext, szStr, nDeep + 1);
     55     szStr[nDeep] = 0;
     56 }
     57 
     58 /*
     59 Created in 2013 10 03
     60 Used in a Array when only one of its member is not sorted
     61 for ascend sequece
     62 */
     63 template <class T>
     64 void SingleSort(T * pHead, int nLength, const int nModifiedAddr)
     65 {
     66     if(pHead == NULL || nLength <= 0)
     67         return;
     68     int nOffSet = 0;
     69     int nFront, nBack;
     70     T tmpVal;
     71     for(int i = nModifiedAddr + 1;i < nLength;++ i)
     72     {
     73         if(pHead[nModifiedAddr] > pHead[i])
     74         {
     75             nOffSet ++;
     76         }
     77         else
     78             break;
     79     }
     80     if(nOffSet != 0)
     81     {
     82         tmpVal = pHead[nModifiedAddr];
     83         nFront = nModifiedAddr;
     84         nBack = nModifiedAddr + nOffSet;
     85         while(nFront != nBack)
     86         {
     87             pHead[nFront] = pHead[nFront + 1];
     88             nFront ++;
     89         }
     90         pHead[nBack] = tmpVal;
     91         return;
     92     }
     93 
     94     for(int i = nModifiedAddr - 1;i >= 0;-- i)
     95     {
     96         if(pHead[nModifiedAddr] < pHead[i])
     97         {
     98             nOffSet --;
     99         }
    100         else
    101             break;
    102     }
    103     if(nOffSet != 0)
    104     {
    105         tmpVal = pHead[nModifiedAddr];
    106         nFront = nModifiedAddr + nOffSet;
    107         nBack = nModifiedAddr;
    108         while(nFront != nBack)
    109         {
    110             pHead[nBack] = pHead[nBack - 1];
    111             nBack --;
    112         }
    113         pHead[nFront] = tmpVal;
    114         return;
    115     }
    116 
    117 }
    118 
    119 int _tmain(int argc, _TCHAR* argv[])
    120 {
    121     unsigned int aCharCountArray[256] = {0};
    122     unsigned char szBuf[256];
    123     DWORD dwReadNum;
    124     vector<HaffmanStruct> vecValidNumberArray;
    125     HANDLE hFile = CreateFile(
    126         _T("C:\record.txt"),
    127         GENERIC_READ,
    128         FILE_SHARE_READ,
    129         0,
    130         OPEN_EXISTING,
    131         FILE_ATTRIBUTE_READONLY,
    132         NULL);
    133     if(hFile == INVALID_HANDLE_VALUE)
    134         return 0;
    135     while(ReadFile(hFile, szBuf, 256, &dwReadNum, NULL))
    136     {
    137         if(dwReadNum == 0)
    138             break;
    139         for(unsigned int i = 0;i < dwReadNum;++ i)
    140         {
    141             //words count
    142             aCharCountArray[szBuf[i]] ++;
    143         }
    144     }
    145     //used in the follow two part's code,temp value
    146     HaffmanStruct ValidStruct;
    147     for(int i = 0;i < 256;++ i)
    148     {
    149         if(aCharCountArray[i] != 0)
    150         {
    151             ValidStruct.val = i;
    152             ValidStruct.ncounts = aCharCountArray[i];
    153             vecValidNumberArray.push_back(ValidStruct);
    154         }
    155     }
    156     sort(vecValidNumberArray.begin(), vecValidNumberArray.end());
    157     while(vecValidNumberArray.size() != 1)
    158     {
    159         ValidStruct.Reset();
    160         ValidStruct.ncounts = vecValidNumberArray[0].ncounts + vecValidNumberArray[1].ncounts;
    161         ValidStruct.lNext = new HaffmanStruct;
    162         *ValidStruct.lNext = vecValidNumberArray[0];
    163         ValidStruct.rNext = new HaffmanStruct;
    164         *ValidStruct.rNext = vecValidNumberArray[1];
    165         vecValidNumberArray.erase(vecValidNumberArray.begin());
    166         vecValidNumberArray[0] = ValidStruct;
    167         SingleSort(&vecValidNumberArray[0], vecValidNumberArray.size(), 0);
    168     }
    169 
    170     char Buf[256] = {0};
    171     ErgodicTree(vecValidNumberArray[0], Buf, 0);
    172 
    173     /*
    174     int vecSize = vecValidNumberArray.size();
    175     for(int i = 0;i < vecSize;++ i)
    176     {
    177         cout << (int)vecValidNumberArray[i].val << ends << 
    178         vecValidNumberArray[i].ncounts << endl;
    179     }*/
    180     CloseHandle(hFile);
    181     system("pause");
    182     return 0;
    183 }
  • 相关阅读:
    JSON和Object数组在js中的转换
    Raphael绘制箭头arrow
    Web后台框架开发
    数据库开发
    docker
    git
    linux
    正则表达式工具
    python模拟ls命令
    python3基础
  • 原文地址:https://www.cnblogs.com/matrix-r/p/3350667.html
Copyright © 2011-2022 走看看