栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

哈夫曼树压缩文件

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

哈夫曼树压缩文件

1.问题描述

准备一个文件,对该文件各种字符进行Huffman编码,将该文件翻译成Huffman文件。

2.基本要求

(1)设计哈夫曼树的结点存储结构

(2)设计编码和破译方法

(3)输入:源文件

(4)输出:Huffman编码文件

3.程序实现:

(1)代码:

#include
#include  
#include
#include
#include 
using namespace std;
// 二叉树结点
struct HuffmanNode {
	HuffmanNode* lChild = nullptr;   //左孩子,一定要初始化,否则就会出很麻烦的问题。
	HuffmanNode* rChild = nullptr;  //右孩子
	char Data = '#';    //存储的字符
	int Weight;   //构建结点的时候存储权重,即频率
	HuffmanNode(char Data, int Weight) {
		this->Data = Data;
		this->Weight = Weight;
	}
	HuffmanNode() {};
};
// 自定义HuffmanNode比较函数
struct HuffmanNodeCompareWeightGreater
{
	bool operator() (const HuffmanNode* a, const HuffmanNode* b)
	{
		return a->Weight > b->Weight;	// 小顶堆
	}
};

class HuffmanTree {
	HuffmanNode* root;
	map  HuffmanMap;  //存储了对应字符和编码的map,解压的时候用与对照还原。
	map  OriginMap; //用于构建哈夫曼树之前统计频率所用,存储的是字符和对应的频率

	//字符频率统计,并存入最初的(字符-编码)map中
	void GiveWeight(char str);
	//构建哈夫曼树,
	void CreateHuffmanTree();
	//文件读取,并统计字符和频率以此来构建OriginMap
	void ReadFile();
	//遍历哈夫曼树所得到的字符以及编码得到新的映射,以字符串s形式存储处理后的Huffman编码
	void DisplayHuffmanTree(HuffmanNode* Temp, string s);
	//Pre为先序遍历,用来检验生成的树是否正确
	void Pre(HuffmanNode* p);
public:
	HuffmanTree() {
		root = new HuffmanNode();
	}
	//文件压缩并写入,对应着源文件和HuffmanMap中的编码一个一个的输出到新的文件
	void ZIP();
	//文件解压,
	void UNZIP();

};

//构建哈夫曼树,
void HuffmanTree::CreateHuffmanTree() {
	//遍历原始的map并根据其键值对逐一构建结点
	priority_queue, HuffmanNodeCompareWeightGreater> HuffmanQueue;
	map::iterator it = OriginMap.begin();
	while (it != OriginMap.end()) {
		//这个每循环一次就取出一组键和值
		char ch = it->first;
		int frequency = it->second;
		HuffmanNode* temp = new HuffmanNode(ch, frequency);  //构建结点,ch即为每个节点存储的字符
		HuffmanQueue.push(temp);
		it++;
	}
	if (!HuffmanQueue.empty())
		if (HuffmanQueue.size() == 1)
			root->lChild = HuffmanQueue.top();
		else if (HuffmanQueue.size() > 1)
			while (HuffmanQueue.size() != 1) {
				HuffmanNode* hfNode_01 = HuffmanQueue.top();
				HuffmanQueue.pop();
				HuffmanNode* hfNode_02 = HuffmanQueue.top();
				HuffmanQueue.pop();
				HuffmanNode* SumNode = new HuffmanNode('#', hfNode_01->Weight + hfNode_02->Weight);
				//权重小的放在左孩子位置
				if (hfNode_01->Weight < hfNode_02->Weight)
				{
					SumNode->lChild = hfNode_01;
					SumNode->rChild = hfNode_02;
				}
				else {
					SumNode->lChild = hfNode_02;
					SumNode->rChild = hfNode_01;
				}
				HuffmanQueue.push(SumNode);
				root = SumNode;
			}
	cout << "哈夫曼处理后的新编码为: " << endl;
	//Pre(root); //检验生成的哈夫曼树是否正确
	//构建哈夫曼字符编码映射HuffmanMap
	string s;
	DisplayHuffmanTree(root, s);

}

void HuffmanTree::DisplayHuffmanTree(HuffmanNode* Temp, string s) {
	if (Temp != nullptr) {
		if (Temp->Data != '#') {
			HuffmanMap.insert(pair(Temp->Data, s));
			cout << Temp->Data << " " << s << "  " << endl;
		}
		DisplayHuffmanTree(Temp->lChild, s.append("0"));
		s.pop_back();      //需要删除上一个递归语句在结尾加上的数字,否则他会影响下面的递归语句
		DisplayHuffmanTree(Temp->rChild, s.append("1"));
	}
}

void HuffmanTree::GiveWeight(char str) {
	//如果OriginMap不含该字符,就将该字符插入map并频率设置为1
	if (OriginMap.count(str) == 0) {
		OriginMap.insert(pair(str, 1));
	}
	//如果OriginMap含有该字符,就将该字符的频率更新+1
	else {
		int frequency = OriginMap[str];
		++frequency;
		OriginMap.erase(str);
		OriginMap.insert(pair(str, frequency));
	}
}
//读文件并统计频率
void HuffmanTree::ReadFile() {
	ifstream ifs("C:\One\DELL\Desktop\压缩文件\待压缩的文件.txt");
	char ch;
	cin.unsetf(ios::skipws);
	if (!ifs.is_open())
		cout << "文件打开失败" << endl;
	while (ifs.get(ch))
		GiveWeight(ch);  // 统计频率
	ifs.close();
}
void HuffmanTree::Pre(HuffmanNode* p) {
	if (p != NULL) {
		cout << p->Weight << " ";
		Pre(p->lChild);
		Pre(p->rChild);
	}
}
void HuffmanTree::ZIP() {
	ReadFile();
	CreateHuffmanTree();
	//对照源文件,把新的编码再存入文件(待完成)
	ifstream ifs("C:\One\DELL\Desktop\压缩文件\待压缩的文件.txt");
	ofstream ofs("C:\One\DELL\Desktop\压缩文件\压缩后的文件.txt");
	if (!ifs.is_open() || !ofs.is_open()) {
		cout << "文件打开失败";
		return;
	}
	char ch;
	cin.unsetf(ios::skipws);
	while (ifs.get(ch))
		ofs << HuffmanMap.find(ch)->second << endl;

	ifs.close();
	ofs.close();

	ofstream ofsHuffmanCode("C:\One\DELL\Desktop\压缩文件\字符和生成的哈夫曼编码.txt");
	map ::iterator it = HuffmanMap.begin();
	while (it != HuffmanMap.end()) {
		ofsHuffmanCode << it->first << " " << it->second << endl;
		it++;
	}
}

void HuffmanTree::UNZIP() {
	ifstream in("C:\One\DELL\Desktop\压缩文件\压缩后的文件.txt");
	string line;
	ofstream out("C:\One\DELL\Desktop\压缩文件\解压后的文件.txt");
	if (in.is_open())
	{
		while (getline(in, line))
		{
			//通过value找 key
			for (map::iterator it = HuffmanMap.begin(); it != HuffmanMap.end(); it++)
			{
				if (it->second == line)
					out << it->first;
			}
		}
	}
	else // 没有该文件
	{
		cout << "文件打开失败" << endl;
	}
	in.close();
	out.close();
}

int main() {
	HuffmanTree hfTree;
	hfTree.ZIP();
	hfTree.UNZIP();
}

以上代码来自:(若有侵权,联系删除)c++哈夫曼编码实现文件的压缩和解压。c++_OnlyForBetter的博客-CSDN博客_哈夫曼编码实现文件的压缩和解压https://blog.csdn.net/hacker_zrq/article/details/116426110?ops_request_misc=&request_id=&biz_id=102&utm_term=%E5%93%88%E5%A4%AB%E6%9B%BC%E6%A0%91%E5%AE%9E%E7%8E%B0%E6%96%87%E4%BB%B6%E5%8E%8B%E7%BC%A9c++&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduweb~default-0-116426110.142%5Ev11%5Epc_search_result_control_group,157%5Ev12%5Econtrol&spm=1018.2226.3001.4187

(2)建立的模型及存储结构:

采用链表结构生成哈夫曼树。

 4.测试与运行:

(1) 若未创建文件则输出结果如下:

 (2)

自写的txt文件如下:

运行结果:

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/934509.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号