Huffman_Tree

来源:互联网 发布:c语言中文网vip百度云 编辑:程序博客网 时间:2024/06/05 05:52

一、哈夫曼树的构造:

1、给出一个数组,以每个元素为基础,创建一个叶子结点数组。

2、从中找出权值最小的两个节点,构建一棵树,这棵树的权值等于两个节点权值之和,

左子树等于权值最小的那个节点,右子树等于权值次小的那个节点。

3、将该树的根放入节点数组原来权值最小的那个位置。

4、不断执行2.3过程。最终得到一颗哈夫曼树。

二、哈夫曼的文件压缩:


代码实现:

  1. #pragma once  
  2. #define _CRT_SECURE_NO_WARNINGS 1  
  3. #include<iostream>  
  4. #include<vector>  
  5. #include<assert.h>  
  6. //#include"HaffmanTree.h"  
  7. using namespace std;  
  8.   
  9. template<class T>  
  10. struct Less  
  11. {  
  12.     bool operator()(const T& l, const T& r)  
  13.     {  
  14.         return l < r;  
  15.     }  
  16. };  
  17.   
  18.   
  19. template<class T>  
  20. struct Greater  
  21. {  
  22.     bool operator()(const T& l, const T& r)  
  23.     {  
  24.         return l > r;  
  25.     }  
  26. };  
  27.   
  28. template<class T>  
  29. struct Less<T*>  
  30. {  
  31.     bool operator()(const T*Nodel, const T*Noder)  
  32.     {  
  33.         return Nodel->_wight < Noder->_wight;  
  34.     }  
  35. };  
  36.   
  37. template<class T,class Continer = Less<T>>//默认为小堆  
  38. class Heap  
  39. {  
  40. public:  
  41.     Heap(){};  
  42.     Heap(const T* a, size_t size,const T& invalid);  
  43.     Heap(vector<T> a);  
  44.     Heap(const vector<T>& v);  
  45.     void Push(const T& x);  
  46.     void Pop();  
  47.     T& GetTop();  
  48.     bool Empty();  
  49.     size_t Size();  
  50.     void HeapSort(T* a, size_t size);  
  51. protected:  
  52.     void _AdjustDown(size_t parent);  
  53.     void _AdjustUp(int child);  
  54. protected:  
  55.     vector<T> _a;  
  56. };  
  57.   
  58. template<class T, class Continer = Less<T>>  
  59. Heap<T, Continer>::Heap(const T* a, size_t size,const T& invalid)  
  60. {  
  61.     _a.reserve(size);  
  62.   
  63.     for (size_t i = 0; i < size; ++i)  
  64.     {  
  65.         if (a[i] != invalid)  
  66.         {  
  67.             _a.push_back(a[i]);  
  68.         }  
  69.     }  
  70.   
  71.     //建堆  
  72.     for (int i = (_a.size() - 2) / 2; i >= 0; i--)  
  73.         //从第一个非叶子结点开始下调,叶子结点可以看作是一个大堆或小堆  
  74.     {  
  75.   
  76.         _AdjustDown(i);  
  77.     }  
  78. }  
  79. template<class T, class Continer = Less<T>>  
  80. Heap<T, Continer>::Heap(vector<T> a)  
  81. {  
  82.     _a.swap(a);  
  83.   
  84.     // 建堆  
  85.     for (int i = (_a.size() - 2) / 2; i >= 0; --i)  
  86.     {  
  87.         _AdjustDown(i);  
  88.     }  
  89. }  
  90. template<class T, class Continer = Less<T>>  
  91. Heap<T, Continer>::Heap(const vector<T>& v)  
  92.     :_a(v)  
  93. {  
  94.     //_a.resize(v.size());  
  95. }  
  96. template<class T, class Continer = Less<T>>  
  97. void Heap<T, Continer>::Push(const T& x)  
  98. {  
  99.     _a.push_back(x);  
  100.     _AdjustUp(_a.size() - 1);  
  101. }  
  102. template<class T, class Continer = Less<T>>  
  103. void Heap<T, Continer>::Pop()  
  104. {  
  105.     assert(!_a.empty());  
  106.     size_t size = _a.size();  
  107.     swap(_a[0], _a[size - 1]);  
  108.     _a.pop_back();  
  109.     _AdjustDown(0);  
  110. }  
  111. template<class T, class Continer = Less<T>>  
  112. T& Heap<T, Continer>::GetTop()  
  113. {  
  114.     return _a[0];  
  115. }  
  116. template<class T, class Continer = Less<T>>  
  117. bool Heap<T, Continer>::Empty()  
  118. {  
  119.     return _a.empty();  
  120. }  
  121. template<class T, class Continer = Less<T>>  
  122. size_t Heap<T, Continer>::Size()  
  123. {  
  124.     return _a.size();  
  125. }  
  126.   
  127. template<class T, class Continer = Less<T>>  
  128. void Heap<T, Continer>::_AdjustDown(size_t parent)  
  129. {  
  130.     Continer _con;  
  131.     size_t child = parent * 2 + 1;  
  132.     size_t size = _a.size();  
  133.     while (child < size)  
  134.     {  
  135.         if (child + 1 < size&&_con(_a[child + 1], _a[child]))  
  136.             //注意这必须是child+1更大或更小,所以把child+1放在前面  
  137.             ++child;  
  138.         if (/*_a[parent] < _a[child]*/_con(_a[child], _a[parent]))  
  139.         {  
  140.             swap(_a[parent], _a[child]);  
  141.             parent = child;  
  142.             child = parent * 2 + 1;  
  143.         }  
  144.         else  
  145.             break;  
  146.     }  
  147. }  
  148. template<class T, class Continer = Less<T>>  
  149. void Heap<T, Continer>::_AdjustUp(int child)  
  150. {  
  151.     Continer _con;  
  152.     int parent = (child - 1) / 2;  
  153.     while (child > 0)  
  154.     {  
  155.         if (_con(_a[child], _a[parent]))  
  156.         {  
  157.             swap(_a[child], _a[parent]);  
  158.             child = parent;  
  159.             parent = (child - 1) / 2;  
  160.         }  
  161.         else  
  162.             break;  
  163.     }  
  164. <p>}</p>  

实现了堆以后实现哈夫曼树:

[cpp] view plain copy
  1. #pragma once  
  2. #include<iostream>  
  3. #include"Heap.h"  
  4. #include"FileComparess.h"  
  5.   
  6. using namespace std;  
  7.   
  8.   
  9. template<class T>  
  10. struct HaffmanNode  
  11. {  
  12.     HaffmanNode<T>* _left;  
  13.     HaffmanNode<T>* _right;  
  14.     T _wight;  
  15.     HaffmanNode(const T& wight)  
  16.         :_left(NULL)  
  17.         , _right(NULL)  
  18.         , _wight(wight)  
  19.     {}  
  20. };  
  21.   
  22.   
  23. template<class T>  
  24. class HaffmanTree  
  25. {  
  26. public:  
  27.     typedef HaffmanNode<T> Node;  
  28.     HaffmanTree(const T* a, size_t size, const T& invalid)  
  29.     {  
  30.         _root = _CreatHaffmanTree(a, size, invalid);  
  31.     }  
  32.     Node* GetRoot()  
  33.     {  
  34.         return _root;  
  35.     }  
  36. protected:  
  37.     Node* _CreatHaffmanTree(const T* a,size_t size, const T& invalid)  
  38.     {  
  39.         Heap<Node*, Less<Node*>> minHeap;  
  40.         for (size_t i = 0; i < size; ++i)  
  41.         {  
  42.             if (a[i] != invalid)  
  43.             {  
  44.                 Node* tmp = new Node(a[i]);  
  45.                 minHeap.Push(tmp);  
  46.             }  
  47.         }  
  48.         while (!minHeap.Empty())  
  49.         {  
  50.             Node* left = minHeap.GetTop();  
  51.             minHeap.Pop();  
  52.             Node* right = NULL;  
  53.             if (!minHeap.Empty())  
  54.             {  
  55.                 right = minHeap.GetTop();  
  56.                 minHeap.Pop();  
  57.             }  
  58.             Node* parent = NULL;  
  59.             if (right)  
  60.             {  
  61.                 parent = new Node(left->_wight + right->_wight);  
  62.             }  
  63.             else  
  64.             {  
  65.                 parent = new Node(left->_wight);  
  66.             }  
  67.             parent->_left = left;  
  68.             parent->_right = right;  
  69.             if (minHeap.Empty())  
  70.             {  
  71.                 return parent;  
  72.             }  
  73.             minHeap.Push(parent);  
  74.         }  
  75.         return NULL;  
  76.     }  
  77. protected:  
  78.     Node* _root;  
  79. }; 

哈夫曼树构造完成开始文件压缩

[cpp] view plain copy
  1. #pragma once  
  2. #define _CRT_SECURE_NO_WARNINGS 1  
  3. #include<iostream>  
  4. #include"HaffmanTree.h"  
  5. using namespace std;  
  6. typedef long LongType;  
  7.   
  8. struct CharInfo  
  9. {  
  10.     unsigned char _ch;  
  11.     LongType _count;  
  12.     string _code;  
  13.     CharInfo(const LongType count = 0 )  
  14.         :_count(count)  
  15.     {}  
  16.     CharInfo(const char ch)  
  17.         :_ch(ch)  
  18.     {}  
  19.     bool operator!=(const CharInfo& c)const  
  20.     {  
  21.         return _count != c._count;  
  22.     }  
  23.     CharInfo operator+(const CharInfo& c)const  
  24.     {  
  25.         return CharInfo(_count + c._count);  
  26.     }  
  27.     bool operator<(const CharInfo& c)const  
  28.     {  
  29.         return _count < c._count;  
  30.     }  
  31. };  
  32.   
  33. class FileComparess  
  34. {  
  35. public:  
  36.     //文件压缩  
  37.     void Comparess(const char* filename)  
  38.     {  
  39.         FILE* fread = fopen(filename, "rb");  
  40.         if (fread == NULL)  
  41.         {  
  42.             cout << "打开待压缩文件失败" << endl;  
  43.             return;  
  44.         }  
  45.         for (int i = 0; i < 256; i++)  
  46.         {  
  47.             _info[i]._ch = i;  
  48.         }  
  49.         unsigned char ch = fgetc(fread); //不能使用char,压缩汉字时的字符出现范围是0~255  
  50.         while (!feof(fread)) //统计各字符出现的次数  
  51.         {  
  52.             //在windows下回车是'\r\n'的组合,遇到‘\r\n’时屏幕上打印换行  
  53.             if (ch == '\r')  
  54.             {  
  55.                 ch = fgetc(fread); //跳过‘\r’  
  56.                 if (ch != '\n')  
  57.                 {  
  58.                     fseek(fread, -1, SEEK_CUR);  
  59.                 }  
  60.             }  
  61.             _info[ch]._count++;  
  62.             ch = fgetc(fread);  
  63.         }  
  64.         HaffmanTree<CharInfo> h(_info, 256, CharInfo());  
  65.         HaffmanNode<CharInfo>* root = h.GetRoot();  
  66.         string str;  
  67.         GenerateHaffmanCode(root, str);  
  68.         //重新打开待压缩文件读  
  69.         fseek(fread, 0, SEEK_SET);  
  70.         ch = fgetc(fread);  
  71.         unsigned char data = 0;   //要写入压缩文件的数据  
  72.         int bitcount = 7;  //标记移位信息  
  73.         //打开文件写压缩后的编码  
  74.         string write(filename);  
  75.         write = write + ".comparess";  
  76.         FILE* fwrite = fopen(write.c_str(), "wb");  
  77.         while (!feof(fread))  
  78.         {  
  79.             if (ch == '\r')  
  80.             {  
  81.                 ch = fgetc(fread);  
  82.                 if (ch != '\n')  
  83.                 {  
  84.                     fseek(fread, -1, SEEK_CUR);  
  85.                 }  
  86.             }  
  87.             const char* cur = _info[ch]._code.c_str();  
  88.             while (*cur)  
  89.             {  
  90.                 if (bitcount >= 0)  
  91.                 {  
  92.                     data = data | ((*cur - '0') << bitcount);  
  93.                     bitcount--;  
  94.                 }  
  95.                 if (bitcount < 0)  
  96.                 {  
  97.                     fputc(data, fwrite);  
  98.                     bitcount = 7;  
  99.                     data = 0;  
  100.                 }  
  101.                 cur++;  
  102.             }  
  103.             ch = fgetc(fread);  
  104.         }  
  105.         fputc(data, fwrite);//最后一个字节没写满8位也要把data写入文件(困扰好久)  
  106.         //写配置文件  
  107.         WriteConfig(filename);  
  108.         fclose(fread);  
  109.         fclose(fwrite);  
  110.     }  
  111.   
  112.   
  113.     //文件解压缩  
  114.     void UnComparess(const char* filename)  
  115.     {  
  116.         CharInfo HNarry[256];  
  117.         //读配置文件  
  118.         ReadConfig(filename, HNarry);  
  119.         //重建Haffman树  
  120.         HaffmanTree<CharInfo> h(HNarry, 256, CharInfo());  
  121.         //遍历树,找叶子结点,写输出文件  
  122.         HaffmanNode<CharInfo>* root = h.GetRoot();  
  123.         HaffmanNode<CharInfo>* cur = root;  
  124.         //打开压缩文件读  
  125.         string comf(filename);  
  126.         comf = comf + ".comparess";  
  127.         FILE* fread = fopen(comf.c_str(), "rb");  
  128.         unsigned char ch = fgetc(fread);  
  129.         FILE* fwrite = fopen("output""wb");  
  130.         int readcount = root->_wight._count;//根节点的_count值就是整棵树字符出现的次数  
  131.         while (readcount)  
  132.         {  
  133.             unsigned int tmp = 1;  
  134.             int bit = 7;   //移动的位数  
  135.             while (bit>=0)  
  136.             {  
  137.                 if (ch & (tmp << bit))  
  138.                 {  
  139.                     cur = cur->_right;  
  140.                     bit--;  
  141.                 }  
  142.                 else  
  143.                 {  
  144.                     cur = cur->_left;  
  145.                     bit--;  
  146.                 }  
  147.                 //找到叶子结点  
  148.                 if (cur->_left == NULL&&cur->_right == NULL)  
  149.                 {  
  150.                     fputc(cur->_wight._ch, fwrite);  
  151.                     cur = root;  
  152.                     readcount--;  
  153.                     //最后一个字符的编码在最后两个字节当中的情况  
  154.                     if (!readcount)  
  155.                     {  
  156.                         break;  
  157.                     }  
  158.                 }  
  159.                   
  160.             }  
  161.             ch = fgetc(fread);  
  162.         }  
  163.         fclose(fread);  
  164.         fclose(fwrite);  
  165.     }  
  166. protected:  
  167.     //得到Haffman编码(后序遍历HaffmanTree)  
  168.     void GenerateHaffmanCode(HaffmanNode<CharInfo>* root, string& code)  
  169.     {  
  170.         if (root == NULL)  
  171.             return;  
  172.         GenerateHaffmanCode(root->_left, code + '0');  
  173.         GenerateHaffmanCode(root->_right, code + '1');  
  174.         root->_wight._code = code;  
  175.         if (root->_left == NULL&&root->_right == NULL)  
  176.         {  
  177.             _info[root->_wight._ch]._code = code;  
  178.         }  
  179.   
  180.     }  
  181.     void WriteConfig(const char* filename)  
  182.     {  
  183.         string conf(filename);  
  184.         conf = conf + "config";  
  185.         FILE* fcon = fopen(conf.c_str(), "wb");  
  186.         for (int i = 0; i < 256; ++i)  
  187.         {  
  188.   
  189.             if (_info[i]._count)  
  190.             {  
  191.                 fputc(_info[i]._ch, fcon);  
  192.                 fputc(',', fcon);  
  193.                 char count[100];  
  194.                 _itoa(_info[i]._count, count, 10);  
  195.                 fputs(count, fcon);  
  196.                 fputc(',', fcon);  
  197.                 fputs(_info[i]._code.c_str(), fcon);  
  198.                 fputc('\n', fcon);  
  199.             }  
  200.         }  
  201.         fclose(fcon);  
  202.     }  
  203.     void ReadConfig(const char* filename, CharInfo* HNarry)  
  204.     {  
  205.         string conf(filename);  
  206.         conf = conf + "config";  
  207.         FILE* fread = fopen(conf.c_str(), "rb");  
  208.         if (fread == NULL)  
  209.         {  
  210.             cout << "打开待压缩文件失败" << endl;  
  211.             return;  
  212.         }  
  213.         char str[100];  
  214.         while (fgets(str, 100, fread))  
  215.         {  
  216.             char* ptr = str;  
  217.             unsigned char index = (unsigned char)*ptr;  
  218.             if (index == '\n'//换行符  
  219.             {  
  220.                 HNarry[index]._ch = index;  
  221.                 fgets(str, 100, fread);  
  222.                 char* ptr = str;  
  223.                 ptr++;  
  224.                 LongType count = 0;//字符的权值,出现的次数  
  225.                 while (*ptr != ',' && *ptr)  
  226.                 {  
  227.                     count *= 10;  
  228.                     count += (*ptr - '0');  
  229.                     ptr++;  
  230.                 }  
  231.                 HNarry[index]._count = count;  
  232.                 ptr++;  
  233.                 string code(ptr);  
  234.                 HNarry[index]._code = code;  
  235.             }  
  236.             else  
  237.             {  
  238.                 HNarry[index]._ch = index;  
  239.                 ptr += 2;  
  240.                 LongType count = 0;//字符的权值,出现的次数  
  241.                 while (*ptr != ',' && *ptr)  
  242.                 {  
  243.                     count *= 10;  
  244.                     count += (*ptr - '0');  
  245.                     ptr++;  
  246.                 }  
  247.                 HNarry[index]._count = count;  
  248.                 ptr++;  
  249.                 string code(ptr);  
  250.                 HNarry[index]._code = code;  
  251.             }  
  252.         }  
  253.     }  
  254. protected:  
  255.     CharInfo _info[256];  
  256. };  

原创粉丝点击