基于Huffman编码的文件压缩
文件压缩(*.zip):简单来说就是让文件原本所占空间变小
主要过程和原理:
压缩步骤
- 1、获取源文件中每个字符出现的次数
- 2、以每个字符出现的次数为权值创建huffman树
- 3、根据Huffman树获取每个字符的编码
- 4、根据每个字符的编码重新改写源文件
压缩原理
- 1 .整个压缩过程的重点都在于Huffman树上,所以主要是构建Huffman树,利用Huffman树的权值来记录文件中每个字符出现的次数
- 2 .Huffman树:最优二叉树,Huffman树是带权路径长度最短的树,权值较大的结点离根较近,所以,用权值来记录每个树出现的次数,并且用编码记录字符所在位置
- 3 .令每一个出现的字符都为二叉树的叶子节点(每条路径只有一个叶子节点),遍历二叉树中每个节点并且记录权值,写到压缩文件中,从而完成对文件的压缩
压缩过程
1.创建Huffman树(HuffmanFile.hpp)
- 注:
- 由于需要用到类模板,所以创建.hpp文件
- 建立小堆:为了获取每个字符最小权值,利用优先级队列建立小堆
- 字符编码:规定路径左为0,路径右为1,以便于记录压缩文件
二叉树实例:
如文件数据:aaaabbddcccccd
2.创建.hzp文件(CompressFile.h&CompressHuff.cpp)
二进制读取文件,统计出256个字符中各字符出现的次数以及字符出现的总次数;
调用Huffman树生成Huffman编码;
按照源文件压缩数据:每8位为一个字节写入压缩文件,当余下的不够一个字节时,在后面补0够一个字节再写入
加入配置信息:字符出现的总次数以及各个字符出现的次数
压缩原理
解压步骤
- 1、获取.hzp压缩文件
- 2、获取压缩文件的信息
- 3、还原Huffman树
- 4、解压缩
解压过程
如果掌握的压缩技巧后,解压的过程相对简单
解压文件属于将压缩文件反向来看:读取压缩文件中的配置信息和二叉树编码,利用resever将二叉树中编码逆置,还原二叉树,从而解压文件
关键代码:
//Huffman树的创建
//1.创建二叉树节点
template<class W>
struct HuffmanTreeNode{
HuffmanTreeNode(const W& weight)
:_pLeft(nullptr)
, _pRight(nullptr)
, _pParent(nullptr)
, _weight(weight)
{}
HuffmanTreeNode<W>* _pLeft;
HuffmanTreeNode<W>* _pRight;
HuffmanTreeNode<W>* _pParent;
W _weight; //权值
};
//2.由于优先级队列默认是大堆,所以我们需要利用仿函数重新定义排序规则
template<class W>
struct Compare{
typedef HuffmanTreeNode<W>* PNode;
bool operator()(const PNode pLeft, const PNode pRight)
{
return pLeft->_weight > pRight->_weight; //仿函数构造小堆
}
};
//3.构造一个Huffman类,对二叉树进行创建排列与销毁
class HuffmanTree{};
//
//压缩与解压中的主要函数 (CompressFile.h)
class FileCompressHuffM
{
public:
FileCompressHuffM();
void CompressFile(const string& strFilePath);
void UNCompressFile(const string& strFilePath);
void WriteHead(FILE* fOut, const string& strFilePath); //文件头部信息
private:
void HuffmanCode(HuffmanTreeNode<CharInfo>* proot);
void GetLine(FILE* fIn, string& strContent);
private:
vector<CharInfo>_charInfo;
};
源代码地址
码云地址:https://gitee.com/CoolShaw_skr/Cpp/tree/master/文件压缩