一、哈夫曼树的构造:
1、给出一个数组,以每个元素为基础,创建一个叶子结点数组。
2、从中找出权值最小的两个节点,构建一棵树,这棵树的权值等于两个节点权值之和,
左子树等于权值最小的那个节点,右子树等于权值次小的那个节点。
3、将该树的根放入节点数组原来权值最小的那个位置。
4、不断执行2.3过程。最终得到一颗哈夫曼树。
二、哈夫曼的文件压缩:
![]()
代码实现:
- #pragma once
- #define _CRT_SECURE_NO_WARNINGS 1
- #include<iostream>
- #include<vector>
- #include<assert.h>
-
- using namespace std;
-
- template<class T>
- struct Less
- {
- bool operator()(const T& l, const T& r)
- {
- return l < r;
- }
- };
-
-
- template<class T>
- struct Greater
- {
- bool operator()(const T& l, const T& r)
- {
- return l > r;
- }
- };
-
- template<class T>
- struct Less<T*>
- {
- bool operator()(const T*Nodel, const T*Noder)
- {
- return Nodel->_wight < Noder->_wight;
- }
- };
-
- template<class T,class Continer = Less<T>>
- class Heap
- {
- public:
- Heap(){};
- Heap(const T* a, size_t size,const T& invalid);
- Heap(vector<T> a);
- Heap(const vector<T>& v);
- void Push(const T& x);
- void Pop();
- T& GetTop();
- bool Empty();
- size_t Size();
- void HeapSort(T* a, size_t size);
- protected:
- void _AdjustDown(size_t parent);
- void _AdjustUp(int child);
- protected:
- vector<T> _a;
- };
-
- template<class T, class Continer = Less<T>>
- Heap<T, Continer>::Heap(const T* a, size_t size,const T& invalid)
- {
- _a.reserve(size);
-
- for (size_t i = 0; i < size; ++i)
- {
- if (a[i] != invalid)
- {
- _a.push_back(a[i]);
- }
- }
-
-
- for (int i = (_a.size() - 2) / 2; i >= 0; i--)
-
- {
-
- _AdjustDown(i);
- }
- }
- template<class T, class Continer = Less<T>>
- Heap<T, Continer>::Heap(vector<T> a)
- {
- _a.swap(a);
-
-
- for (int i = (_a.size() - 2) / 2; i >= 0; --i)
- {
- _AdjustDown(i);
- }
- }
- template<class T, class Continer = Less<T>>
- Heap<T, Continer>::Heap(const vector<T>& v)
- :_a(v)
- {
-
- }
- template<class T, class Continer = Less<T>>
- void Heap<T, Continer>::Push(const T& x)
- {
- _a.push_back(x);
- _AdjustUp(_a.size() - 1);
- }
- template<class T, class Continer = Less<T>>
- void Heap<T, Continer>::Pop()
- {
- assert(!_a.empty());
- size_t size = _a.size();
- swap(_a[0], _a[size - 1]);
- _a.pop_back();
- _AdjustDown(0);
- }
- template<class T, class Continer = Less<T>>
- T& Heap<T, Continer>::GetTop()
- {
- return _a[0];
- }
- template<class T, class Continer = Less<T>>
- bool Heap<T, Continer>::Empty()
- {
- return _a.empty();
- }
- template<class T, class Continer = Less<T>>
- size_t Heap<T, Continer>::Size()
- {
- return _a.size();
- }
-
- template<class T, class Continer = Less<T>>
- void Heap<T, Continer>::_AdjustDown(size_t parent)
- {
- Continer _con;
- size_t child = parent * 2 + 1;
- size_t size = _a.size();
- while (child < size)
- {
- if (child + 1 < size&&_con(_a[child + 1], _a[child]))
-
- ++child;
- if (_con(_a[child], _a[parent]))
- {
- swap(_a[parent], _a[child]);
- parent = child;
- child = parent * 2 + 1;
- }
- else
- break;
- }
- }
- template<class T, class Continer = Less<T>>
- void Heap<T, Continer>::_AdjustUp(int child)
- {
- Continer _con;
- int parent = (child - 1) / 2;
- while (child > 0)
- {
- if (_con(_a[child], _a[parent]))
- {
- swap(_a[child], _a[parent]);
- child = parent;
- parent = (child - 1) / 2;
- }
- else
- break;
- }
- <p>}</p>
实现了堆以后实现哈夫曼树:
- #pragma once
- #include<iostream>
- #include"Heap.h"
- #include"FileComparess.h"
-
- using namespace std;
-
-
- template<class T>
- struct HaffmanNode
- {
- HaffmanNode<T>* _left;
- HaffmanNode<T>* _right;
- T _wight;
- HaffmanNode(const T& wight)
- :_left(NULL)
- , _right(NULL)
- , _wight(wight)
- {}
- };
-
-
- template<class T>
- class HaffmanTree
- {
- public:
- typedef HaffmanNode<T> Node;
- HaffmanTree(const T* a, size_t size, const T& invalid)
- {
- _root = _CreatHaffmanTree(a, size, invalid);
- }
- Node* GetRoot()
- {
- return _root;
- }
- protected:
- Node* _CreatHaffmanTree(const T* a,size_t size, const T& invalid)
- {
- Heap<Node*, Less<Node*>> minHeap;
- for (size_t i = 0; i < size; ++i)
- {
- if (a[i] != invalid)
- {
- Node* tmp = new Node(a[i]);
- minHeap.Push(tmp);
- }
- }
- while (!minHeap.Empty())
- {
- Node* left = minHeap.GetTop();
- minHeap.Pop();
- Node* right = NULL;
- if (!minHeap.Empty())
- {
- right = minHeap.GetTop();
- minHeap.Pop();
- }
- Node* parent = NULL;
- if (right)
- {
- parent = new Node(left->_wight + right->_wight);
- }
- else
- {
- parent = new Node(left->_wight);
- }
- parent->_left = left;
- parent->_right = right;
- if (minHeap.Empty())
- {
- return parent;
- }
- minHeap.Push(parent);
- }
- return NULL;
- }
- protected:
- Node* _root;
- };
哈夫曼树构造完成开始文件压缩:
- #pragma once
- #define _CRT_SECURE_NO_WARNINGS 1
- #include<iostream>
- #include"HaffmanTree.h"
- using namespace std;
- typedef long LongType;
-
- struct CharInfo
- {
- unsigned char _ch;
- LongType _count;
- string _code;
- CharInfo(const LongType count = 0 )
- :_count(count)
- {}
- CharInfo(const char ch)
- :_ch(ch)
- {}
- bool operator!=(const CharInfo& c)const
- {
- return _count != c._count;
- }
- CharInfo operator+(const CharInfo& c)const
- {
- return CharInfo(_count + c._count);
- }
- bool operator<(const CharInfo& c)const
- {
- return _count < c._count;
- }
- };
-
- class FileComparess
- {
- public:
-
- void Comparess(const char* filename)
- {
- FILE* fread = fopen(filename, "rb");
- if (fread == NULL)
- {
- cout << "打开待压缩文件失败" << endl;
- return;
- }
- for (int i = 0; i < 256; i++)
- {
- _info[i]._ch = i;
- }
- unsigned char ch = fgetc(fread);
- while (!feof(fread))
- {
-
- if (ch == '\r')
- {
- ch = fgetc(fread);
- if (ch != '\n')
- {
- fseek(fread, -1, SEEK_CUR);
- }
- }
- _info[ch]._count++;
- ch = fgetc(fread);
- }
- HaffmanTree<CharInfo> h(_info, 256, CharInfo());
- HaffmanNode<CharInfo>* root = h.GetRoot();
- string str;
- GenerateHaffmanCode(root, str);
-
- fseek(fread, 0, SEEK_SET);
- ch = fgetc(fread);
- unsigned char data = 0;
- int bitcount = 7;
-
- string write(filename);
- write = write + ".comparess";
- FILE* fwrite = fopen(write.c_str(), "wb");
- while (!feof(fread))
- {
- if (ch == '\r')
- {
- ch = fgetc(fread);
- if (ch != '\n')
- {
- fseek(fread, -1, SEEK_CUR);
- }
- }
- const char* cur = _info[ch]._code.c_str();
- while (*cur)
- {
- if (bitcount >= 0)
- {
- data = data | ((*cur - '0') << bitcount);
- bitcount--;
- }
- if (bitcount < 0)
- {
- fputc(data, fwrite);
- bitcount = 7;
- data = 0;
- }
- cur++;
- }
- ch = fgetc(fread);
- }
- fputc(data, fwrite);
-
- WriteConfig(filename);
- fclose(fread);
- fclose(fwrite);
- }
-
-
-
- void UnComparess(const char* filename)
- {
- CharInfo HNarry[256];
-
- ReadConfig(filename, HNarry);
-
- HaffmanTree<CharInfo> h(HNarry, 256, CharInfo());
-
- HaffmanNode<CharInfo>* root = h.GetRoot();
- HaffmanNode<CharInfo>* cur = root;
-
- string comf(filename);
- comf = comf + ".comparess";
- FILE* fread = fopen(comf.c_str(), "rb");
- unsigned char ch = fgetc(fread);
- FILE* fwrite = fopen("output", "wb");
- int readcount = root->_wight._count;
- while (readcount)
- {
- unsigned int tmp = 1;
- int bit = 7;
- while (bit>=0)
- {
- if (ch & (tmp << bit))
- {
- cur = cur->_right;
- bit--;
- }
- else
- {
- cur = cur->_left;
- bit--;
- }
-
- if (cur->_left == NULL&&cur->_right == NULL)
- {
- fputc(cur->_wight._ch, fwrite);
- cur = root;
- readcount--;
-
- if (!readcount)
- {
- break;
- }
- }
-
- }
- ch = fgetc(fread);
- }
- fclose(fread);
- fclose(fwrite);
- }
- protected:
-
- void GenerateHaffmanCode(HaffmanNode<CharInfo>* root, string& code)
- {
- if (root == NULL)
- return;
- GenerateHaffmanCode(root->_left, code + '0');
- GenerateHaffmanCode(root->_right, code + '1');
- root->_wight._code = code;
- if (root->_left == NULL&&root->_right == NULL)
- {
- _info[root->_wight._ch]._code = code;
- }
-
- }
- void WriteConfig(const char* filename)
- {
- string conf(filename);
- conf = conf + "config";
- FILE* fcon = fopen(conf.c_str(), "wb");
- for (int i = 0; i < 256; ++i)
- {
-
- if (_info[i]._count)
- {
- fputc(_info[i]._ch, fcon);
- fputc(',', fcon);
- char count[100];
- _itoa(_info[i]._count, count, 10);
- fputs(count, fcon);
- fputc(',', fcon);
- fputs(_info[i]._code.c_str(), fcon);
- fputc('\n', fcon);
- }
- }
- fclose(fcon);
- }
- void ReadConfig(const char* filename, CharInfo* HNarry)
- {
- string conf(filename);
- conf = conf + "config";
- FILE* fread = fopen(conf.c_str(), "rb");
- if (fread == NULL)
- {
- cout << "打开待压缩文件失败" << endl;
- return;
- }
- char str[100];
- while (fgets(str, 100, fread))
- {
- char* ptr = str;
- unsigned char index = (unsigned char)*ptr;
- if (index == '\n')
- {
- HNarry[index]._ch = index;
- fgets(str, 100, fread);
- char* ptr = str;
- ptr++;
- LongType count = 0;
- while (*ptr != ',' && *ptr)
- {
- count *= 10;
- count += (*ptr - '0');
- ptr++;
- }
- HNarry[index]._count = count;
- ptr++;
- string code(ptr);
- HNarry[index]._code = code;
- }
- else
- {
- HNarry[index]._ch = index;
- ptr += 2;
- LongType count = 0;
- while (*ptr != ',' && *ptr)
- {
- count *= 10;
- count += (*ptr - '0');
- ptr++;
- }
- HNarry[index]._count = count;
- ptr++;
- string code(ptr);
- HNarry[index]._code = code;
- }
- }
- }
- protected:
- CharInfo _info[256];
- };