基于Huffman编码的文件压缩项目

Posted 蚍蜉撼树谈何易

tags:

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

文件压缩概念及目的

概念:文件压缩是指在不丢失有用信息的前提下,缩减数据量以减少存储空间,提高其传输、存储和处理效率,或着按照一定的算法对文件中数据进行重新组织,减少数据的冗余和存储的空间的一种技术方法
目的:

  1. 紧缩数据存储容量,减少存储空间
  2. 可以提高数据传输的速度,减少带宽占用量,提高通讯效率
  3. 对数据的一种加密保护,增强数据在传输过程中的安全性
    压缩分类:有损压缩、无损压缩

设计思路

了解Huffman树

什么是Huffman树?
将带权路径长度最短的二叉树称为Huffman树。
如何构建?
1.由给定的n个权值构建n棵只含有根节点的二叉树森林集合。
2.重复以下步骤,直至二叉树森林中只含有一颗树为止。
2.1.在集合中选取两个权值最小的二叉树,作为左右子树构造一棵新的二叉树,同时将这两棵树的根节点权值变为左右子树权值之和。
2.2.将2.1中选取的两个权值最小二叉树从集合中删除
2.3.同时将这两个二叉树生成新二叉树放置在集合中,

选取的数据结构

构建Huffman选取的数据结构

因为生成的Huffman树默认权值是从顶层到底层权值是依次递减的。所以我们这里采用优先级队列来实现它,但由于其默认采用的大堆存储方法,所以我们此时必须利用仿函数来采取自定义比较方式

保存字符及对应的编码

文件压缩的类及对应方法

构建Huffman树以及对应编码规则

获取每个字符对应的压缩码

void File_Compress::Generate_Huffmancode(Huffman_Tree<Byte_Info>* root)
{
	if (nullptr == root)
	{
		return;
	}
	
	if (root->left == nullptr && root->right == nullptr)
	{
		Huffman_Tree<Byte_Info>*cur = root;
		Huffman_Tree<Byte_Info>* parent = root->parent;
		std::string &str_code = file_byteinfo[cur->weight.ch].str_code;
		while (parent)
		{
			if (cur == parent->left)
			{
				str_code += '0';
			}
			else
			{
				str_code += '1';
			}
			cur = parent;
			parent = cur->parent;
		}
		reverse(str_code.begin(), str_code.end());
	}
	Generate_Huffmancode(root->left);
	Generate_Huffmancode(root->right);
}

书写压缩文件

1.将文件的类型写出来
2.将文件对应的字符类的个数写出来
3.将每个字符对应的个数写出来
4,用得到的编码替换字符




解码

思路:
1.根据压缩保存的文件类型先来获取到文件类型,创建文件
2.读取第二行存储的行的大小,字符的种类个数
3.根据里面的权值来重建Huffman树
4.读取压缩数据,结合Huffman树进行解压缩。

bool File_Compress::Un_Compress(const std::string& FilePath)
{
	//1.从压缩文件中读取我们解压缩所要用到的信息。
	FILE* Fin = fopen(FilePath.c_str(), "rb");
	if (Fin == nullptr)
	{
		std::cout << "open error" << std::endl;
	}
	//读取文件后缀
	string PostFix;
	Get_line(Fin, PostFix);
	//读取频次信息总行数
	string strcontent;
	Get_line(Fin, strcontent);
	size_t linecount = atoi(strcontent.c_str());
	strcontent = "";
	for (size_t i = 0; i < linecount; ++i)
	{
		Get_line(Fin, strcontent);
		//证明其读到一个换行符
		if ("" == strcontent)
		{
			strcontent += "\\n";
			
			Get_line(Fin, strcontent);
		}
           //file_byteinfo[strcontent[0]].ch = strcontent[0];
		   file_byteinfo[(uchar)strcontent[0]].appera_count = atoi(strcontent.c_str() + 2);
		   strcontent = "";	
	}
	//2.恢复Huffman树
	Huffman<Byte_Info> ht;
	Byte_Info Invalid;
	ht.Create_Huffman(file_byteinfo, 256, Invalid);
	//3.读取压缩数据,结合Huffman树进行解压缩
	string filename("3");
	filename += PostFix;
	FILE* fout = fopen(filename.c_str(), "wb");
	uchar buf[1024];
	uchar bitcount = 0;
	Huffman_Tree <Byte_Info>* cur = ht.Getroot();
	const int file_size = cur->weight.appera_count;
	int compress_size = 0;
	while (true)
	{
		size_t rdsize = fread(buf, 1, 1024, Fin);
		if (0 == rdsize)
		{
			break;
		}
		for (int i = 0; i < rdsize; ++i)
		{
			uchar ch = buf[i];
			bitcount = 0;
			while (bitcount < 8)
			{
				
				if (ch & 0x80)
				{
					cur = cur->right;
				}
				else
				{
					cur = cur->left;
				}
				if (nullptr ==  cur->left && nullptr ==  cur->right)
				{
					fputc(cur->weight.ch, fout);
					cur = ht.Getroot();
					compress_size++;
					//为了避免读取脏数据
					if (compress_size == file_size)
					{
						break;
					}
				}
				bitcount++;
				ch <<= 1;
			}

		}
	}
	fclose(Fin);
	fclose(fout);
	return true;
}

效果图

文本文件:

以上是关于基于Huffman编码的文件压缩项目的主要内容,如果未能解决你的问题,请参考以下文章

[保姆级万字教程]打造最迷人的S曲线----带你从零手撕基于Huffman编码的文件压缩项目

[保姆级万字教程]打造最迷人的S曲线----带你从零手撕基于Huffman编码的文件压缩项目

[保姆级万字教程]打造最迷人的S曲线----带你从零手撕基于Huffman编码的文件压缩项目

[保姆级万字教程]打造最迷人的S曲线----带你从零手撕基于Huffman编码的文件压缩项目

基于Huffman树的文件压缩

基于Huffman树的文件压缩