C++基于Huffman编码实现文件压缩和解压

实验要求实验目的利用Huffman编码实现文件的压缩和解压实验要求通过键盘输入原文件路径,对原文件进行压缩操作通过键盘输压缩文件路径,对压缩文件进行解压操作程序思路压缩文件过程读入一个文本文件,计算其中每一个字符出现的次数。根据步骤1得到的数据,生成哈夫曼编码树,并得到每种出现字符的具体编码。将哈夫曼树存储在树信息文件中。要求使用哈夫曼树的顺序表示法存储树的结构(不存储...
摘要由CSDN通过智能技术生成

实验要求

实验目的

利用Huffman编码实现文件的压缩和解压

实验要求

  1. 通过键盘输入原文件路径,对原文件进行压缩操作
  2. 通过键盘输压缩文件路径,对压缩文件进行解压操作

程序思路

压缩文件过程
  1. 读入一个文本文件,计算其中每一个字符出现的次数。
  2. 根据步骤1得到的数据,生成哈夫曼编码树,并得到每种出现字符的具体编码。
  3. 将哈夫曼树存储在树信息文件中。
    要求使用哈夫曼树的顺序表示法存储树的结构(不存储字母的频率信息)
  4. 根据步骤2得到的哈夫曼编码对文本文件进行压缩,并将压缩内容写入输出文件中。
如何将Huffman树存储在树信息文件中

例子
请勿存储节点频率信息,仅需叶节点对应的字母信息即可。
如上图的树结构(先序遍历)可表示为101100101011000对应0的位置即是叶节点的位置,此处仅需存储叶节点的信息(其他信息对解码无用),即各个字母的ASCII码,可按先序遍历的顺序依次存储在树结构后面。第一个int(4个字节),可存储所有节点的个数,便于定位字母的ASCII码的起始位置。

解压文件过程
  1. 读入树信息文件,还原成Huffman树
  2. 读入压缩文件,根据Huffman编码树进行解压
  3. 将步骤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);
}

/*插入结点*/<
  • 13
    点赞
  • 94
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
好的,下面是代码实现: ```c++ #include <iostream> #include <fstream> #include <queue> #include <map> using namespace std; // 定义 Huffman 树节点 struct HuffmanTreeNode { int weight; // 权值 char ch; // 字符 HuffmanTreeNode *left, *right; // 左右子节点 HuffmanTreeNode(int weight, char ch, HuffmanTreeNode *left, HuffmanTreeNode *right) { this->weight = weight; this->ch = ch; this->left = left; this->right = right; } }; // Huffman 编码 class HuffmanEncoding { public: HuffmanEncoding() {} // 压缩文件 void compress(const string& input_file, const string& output_file) { // 统计字符出现频率 map<char, int> freq_map = get_freq_map(input_file); // 构建 HuffmanHuffmanTreeNode *root = build_huffman_tree(freq_map); // 生成字符编码表 map<char, string> encoding_map = generate_encoding_map(root); // 压缩文件 compress_file(input_file, output_file, encoding_map); // 释放 Huffman 树节点 release_huffman_tree(root); } // 解压文件 void decompress(const string& input_file, const string& output_file) { // 解析 HuffmanHuffmanTreeNode *root = parse_huffman_tree(input_file); // 解压文件 decompress_file(input_file, output_file, root); // 释放 Huffman 树节点 release_huffman_tree(root); } private: // 统计字符出现频率 map<char, int> get_freq_map(const string& input_file) { map<char, int> freq_map; ifstream fin(input_file, ios::in | ios::binary); char ch; while (fin.get(ch)) { freq_map[ch]++; } fin.close(); return freq_map; } // 构建 HuffmanHuffmanTreeNode *build_huffman_tree(const map<char, int>& freq_map) { auto cmp = [](HuffmanTreeNode *a, HuffmanTreeNode *b) { return a->weight > b->weight; }; priority_queue<HuffmanTreeNode*, vector<HuffmanTreeNode*>, decltype(cmp)> pq(cmp); for (auto& freq_pair : freq_map) { pq.push(new HuffmanTreeNode(freq_pair.second, freq_pair.first, nullptr, nullptr)); } while (pq.size() > 1) { HuffmanTreeNode *left = pq.top(); pq.pop(); HuffmanTreeNode *right = pq.top(); pq.pop(); pq.push(new HuffmanTreeNode(left->weight + right->weight, '\0', left, right)); } HuffmanTreeNode *root = pq.top(); pq.pop(); return root; } // 生成字符编码表 map<char, string> generate_encoding_map(HuffmanTreeNode *root) { map<char, string> encoding_map; string code; generate_encoding_map_helper(root, code, encoding_map); return encoding_map; } void generate_encoding_map_helper(HuffmanTreeNode *node, string& code, map<char, string>& encoding_map) { if (node == nullptr) { return; } if (node->left == nullptr && node->right == nullptr) { encoding_map[node->ch] = code; return; } code.push_back('0'); generate_encoding_map_helper(node->left, code, encoding_map); code.pop_back(); code.push_back('1'); generate_encoding_map_helper(node->right, code, encoding_map); code.pop_back(); } // 压缩文件 void compress_file(const string& input_file, const string& output_file, const map<char, string>& encoding_map) { ifstream fin(input_file, ios::in | ios::binary); ofstream fout(output_file, ios::out | ios::binary); char ch; string code; while (fin.get(ch)) { code += encoding_map.at(ch); while (code.length() >= 8) { char byte = 0; for (int i = 0; i < 8; i++) { if (code[i] == '1') { byte |= (1 << (7 - i)); } } fout.put(byte); code.erase(0, 8); } } if (!code.empty()) { char byte = 0; for (int i = 0; i < code.length(); i++) { if (code[i] == '1') { byte |= (1 << (7 - i)); } } fout.put(byte); } fin.close(); fout.close(); } // 解析 HuffmanHuffmanTreeNode *parse_huffman_tree(const string& input_file) { ifstream fin(input_file, ios::in | ios::binary); char ch; fin.get(ch); if (ch == '\0') { fin.close(); return nullptr; } HuffmanTreeNode *root = new HuffmanTreeNode(0, '\0', nullptr, nullptr); parse_huffman_tree_helper(root, fin); fin.close(); return root; } void parse_huffman_tree_helper(HuffmanTreeNode *node, ifstream& fin) { char ch; fin.get(ch); if (ch == '1') { node->left = new HuffmanTreeNode(0, '\0', nullptr, nullptr); parse_huffman_tree_helper(node->left, fin); } fin.get(ch); if (ch == '1') { node->right = new HuffmanTreeNode(0, '\0', nullptr, nullptr); parse_huffman_tree_helper(node->right, fin); } } // 解压文件 void decompress_file(const string& input_file, const string& output_file, HuffmanTreeNode *root) { ifstream fin(input_file, ios::in | ios::binary); ofstream fout(output_file, ios::out | ios::binary); if (root == nullptr) { fin.close(); fout.close(); return; } HuffmanTreeNode *node = root; char ch; while (fin.get(ch)) { for (int i = 7; i >= 0; i--) { if ((ch >> i) & 1) { node = node->right; } else { node = node->left; } if (node->left == nullptr && node->right == nullptr) { fout.put(node->ch); node = root; } } } fin.close(); fout.close(); } // 释放 Huffman 树节点 void release_huffman_tree(HuffmanTreeNode *node) { if (node == nullptr) { return; } release_huffman_tree(node->left); release_huffman_tree(node->right); delete node; } }; int main() { HuffmanEncoding huffman; string input_file = "input.txt"; string output_file = "output.bin"; // 压缩文件 huffman.compress(input_file, output_file); // 解压文件 huffman.decompress(output_file, "output.txt"); return 0; } ``` 在这个例子中,我们使用了 C++ 的 STL 库中的 `map`、`priority_queue` 和文件流相关的类来实现 Huffman 编码。该程序可以读取指定的文件生成 Huffman 编码并将其写入到输出文件中。另外,还可以读取 Huffman 编码并将其解压回原始文件
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值