文件压缩——哈夫曼树编码

Posted shy0322

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了文件压缩——哈夫曼树编码相关的知识,希望对你有一定的参考价值。

何谓哈夫曼树?——

  百度百科:给定n个权值作为n个叶子结点,构造一棵二叉树,若带权路径长度达到最小,称这样的二叉树为最优二叉树,也称为哈夫曼树(Huffman Tree)。哈夫曼树是带权路径长度最短的树,权值较大的结点离根较近。

哈夫曼树的应用?——

  哈夫曼编码 与 哈夫曼译码。

哈夫曼树为基础的项目?——

  文件压缩。

文件压缩分两种:1.有损压缩。2.无损压缩。

哈夫曼树为核心算法的压缩方式是无损压缩。

其实我们windows常用的zip类型的压缩包底层,哈夫曼树就是核心算法之一(当然不全是)。

 

生成一棵哈夫曼树并进行哈夫曼编码,再用哈弗曼编码和哈夫曼树还原——

比如看这条语句:aaaabbbccd

1.首先统计文件字符出现次数——

a 4

b 3

c 2

d 1

2.构建huffman树——见图

  技术分享图片

3.根据huffman树生成huffman编码(huffman code)

  a --- 0   b --- 11 c --- 101  d --- 100

  aaaabbbccd --- 0000111111101101100
4.压缩——
test.txt -----> test.huffman
每一个字符都有唯一的路劲,那么每一个字符都有唯一的编码,那么就可以替换完成无损压缩。
5.解压缩——
使用test.huffman------->test.txt

 

那么详细的让我们看代码——

.h文件——

 该类模拟生成哈夫曼树。

技术分享图片
 1 #pragma once
 2 
 3 #include<queue>
 4 
 5 template<typename W>
 6 struct HuffmanTreeNode
 7 {
 8     W val;
 9     HuffmanTreeNode* right;
10     HuffmanTreeNode* left;
11 };
12 
13 //堆——优先级队列。priority_queue
14 
15 template<typename W,typename T>
16 class HuffmanTree
17 {
18     //放在内部,方便且安全
19     typedef HuffmanTreeNode Node;
20 public:
21     //优先队列中放的是结点的指针。
22     //因为我放的是指针,但是比较的时候不能比较指针啊。
23     //所以在这里我需要写一个仿函数。
24     //让他用我的仿函数比较。但是要注意,仿函数是第三个模板参数,所以第二个模板参数还是要一样的。
25 
26     //因为我们要杜绝出现出现次数为0的情况,这种情况不会被我们统计但是如果不管会占空间。
27     HuffmanTree(W* a,size_t n,const T& invalid);
28 
29     //生成完哈夫曼树后那么接下来就是要生成哈夫曼编码了
30     //生成哈夫曼编码的方法
31     //1.三叉链法。添加一个parents指针在HuffmanNode结构体中,并且注意初始化。
32     //2.递归,左0右1。递归方法放在FileCompress类中。
33 
34     //因为如果利用递归法,就很有可能需要在最后,将根的哈夫曼码变成当前结点结构体中的哈夫曼码。
35     //所以需要类提供一个接口
36     //返回root
37     Node* GetRoot();
38 
39     ~HuffmanTree();
40     //因为涉及树,所以删除很有可能需要调用递归,要自觉习惯用一个函数来完成析构任务。
41     void destory(Node* root);
42 private:
43     //暂时用不到拷贝构造和=运算符重载
44     //所以直接用防拷贝的方法。
45     HuffmanTree(const HuffmanTree<W> &t);
46     HuffmanTree<W>& operator=(const HuffmanTree<T> &t);
47 protected:
48     Node* root;
49 };
HuffmanTree.h

 

接下来是用例案例——

模拟实现文件解析类。

技术分享图片
 1 #pragma once
 2 
 3 #include<string>
 4 #include"HuffmanTree.h"
 5 using namespace std;
 6 
 7 //一个字符的信息——
 8 //我们会将这个值统计好传过去来生成哈夫曼树。
 9 //但同时我们也知道哈夫曼树中有W的加的操作,>的操作,!=的操作。
10 //所以我们还需要重载+运算符,>运算符,!=运算符。
11 struct CharInfo
12 {
13     char _ch;
14     long long _count;
15     string _code;
16     CharInfo operator+(const CharInfo& info);
17     bool operator>(const CharInfo& info);
18     bool operator!=(const CharInfo& info);
19 };
20 
21 class FileCompress
22 {
23 public:
24     //构造函数就是写死,初始化哈希表。
25     FileCompress();
26     //压缩
27     //1.首先要统计文件中字符出现的次数。
28     //2.用IO流的方式读字符串---因为是读,所以是ifstream,因为要从文件里读。
29     //C++reference里有些,构造函数就直接讲字符串当做参数(字符串实际为一个文件),读字符就用get。
30     void Compress(const char *file);
31     //解压缩
32     void Uncompress(const char *file);
33     void GenerateHuffmanCode(HuffmanTreeNode<char> *node);
34 protected:
35     CharInfo _hashInfos[256];//用来存放各个字符。
36 };
FileCompress.h

持续更新...






以上是关于文件压缩——哈夫曼树编码的主要内容,如果未能解决你的问题,请参考以下文章

基于哈夫曼树的任意文件解压缩实现

哈夫曼编码译码器 java

哈夫曼编码C语言实现

哈夫曼树的应用

(王道408考研数据结构)第五章树-第四节3:哈夫曼树基本概念构造和哈夫曼编码

C++程序编写压缩器/解压器(长度-游程编码的压缩/解压+霍夫曼编码压缩/解压 (霍夫曼树))