实验要求
实验目的
利用Huffman编码实现文件的压缩和解压
实验要求
- 通过键盘输入原文件路径,对原文件进行压缩操作
- 通过键盘输压缩文件路径,对压缩文件进行解压操作
程序思路
压缩文件过程
- 读入一个文本文件,计算其中每一个字符出现的次数。
- 根据步骤1得到的数据,生成哈夫曼编码树,并得到每种出现字符的具体编码。
- 将哈夫曼树存储在树信息文件中。
要求使用哈夫曼树的顺序表示法存储树的结构(不存储字母的频率信息) - 根据步骤2得到的哈夫曼编码对文本文件进行压缩,并将压缩内容写入输出文件中。
如何将Huffman树存储在树信息文件中
请勿存储节点频率信息,仅需叶节点对应的字母信息即可。
如上图的树结构(先序遍历)可表示为101100101011000对应0的位置即是叶节点的位置,此处仅需存储叶节点的信息(其他信息对解码无用),即各个字母的ASCII码,可按先序遍历的顺序依次存储在树结构后面。第一个int(4个字节),可存储所有节点的个数,便于定位字母的ASCII码的起始位置。
解压文件过程
- 读入树信息文件,还原成Huffman树
- 读入压缩文件,根据Huffman编码树进行解压
- 将步骤2得到的内容写入新的文本文件中
代码
HuffmanCompressAndUn.h
#pragma once
#include <iostream>
#include <string>
using namespace std;
//全局变量,重构Huffman树时需要
int leafArrIndex = 0;
int strIndex = 0;
int nodeIndex = 0;
/*Huffman结点*/
class TreeNode {
public:
unsigned char it; //结点元素
double weight; //结点权重
int parent, lchild, rchild; //结点的父结点及左右子结点
TreeNode() {
parent = lchild = rchild = -1;
}
TreeNode(const unsigned char &data, const double &wt) {
it = data;
weight = wt;
parent = lchild = rchild = -1;
}
};
/*编码类 存放每个字母的编码*/
class Code {
public:
char *ptr;
const int length;
Code() : length(20) {
ptr = new char[length]; }
~Code() {
delete[] ptr; }
};
/*Huffman树*/
class HuffmanTree {
private:
int maxSize; //数组最大值
int findPosition(const unsigned char &) const; //返回字符在arrayTree[]中的位置
void insert(const unsigned char&, const double&); //插入结点
void buildHuffmanTree(); //创建哈夫曼树
void writeCodeToFile(const char *); //将Huffman树存储到树信息文件中
void writeTreeStructureToFile(const int &, FILE*); //将树结构信息存储到树信息文件中
void writeLeafToFile(const int &, FILE*); //将叶结点信息存储到树信息文件中
public:
int currsize; //当前数组大小
TreeNode *arrayTree; //哈夫曼结点数组
Code *codeArray; //存放每个叶结点的编码,大小为currsize
HuffmanTree() {
maxSize = 1000;
arrayTree = new TreeNode[maxSize];
currsize = 0;
}
void run(const char*, const char*); //编码用,建树 编码 写入树信息文件
void reBuildHuffmanTree(const unsigned char*, const int*, int); //解码用,根据树信息文件重建Huffman树
void createHuffmanCode(); //编解码均可用,创建Huffman编码
void reBuildArray(char **, unsigned char *, int); //解码用,重建结点数组
};
/*run函数的实现*/
void HuffmanTree::run(const char *inFilename, const char *outFilename) {
FILE *fo;
fopen_s(&fo, inFilename, "rb"); //读入待压缩文件 读取二进制文件
if (fo == NULL) {
cerr << " Can not open!" << endl;
exit(1);
}
unsigned char ch = fgetc(fo); //读取一个字符
int pos;
while (!feof(fo)) {
// 从文件当中读入字符 直到文件结束,并且统计字符个数
pos = findPosition(ch);
if (pos != -1)
arrayTree[pos].weight++;
else
insert(ch, 1); //新插入一个 权重为1
ch = fgetc(fo);
}
buildHuffmanTree(); //构造huffman树
createHuffmanCode(); //对统计字符进行编码
writeCodeToFile(outFilename); //将编码表存入文件
fclose(fo);
}
/*插入结点*/<