文件压缩

//HuffmanTree.h

#include <iostream>
#include <string.h>
#include "Heap.h"
using namespace std;
template<class T>
struct  HuffmanNode
{
	HuffmanNode<T>*  _parent;
	HuffmanNode<T>*  _left;
	HuffmanNode<T>*  _right;
	T  _weight;
	HuffmanNode(const T& x)
		:_parent(NULL)
		, _left(NULL)
		, _right(NULL)
		, _weight(x)
	{
	}
};
template <class T>
class  Huffman
{
	typedef  HuffmanNode<T>   Node;
public:
	Huffman()
		:_root(NULL)
	{}
	Huffman(T* a,size_t size,const T& invalid)
	{
		assert(a);
		struct  Less
		{
			bool  operator()(const Node* left, const Node* right)
			{
				return left->_weight < right->_weight;
			}
		};
		Heap<Node*, Less>  MinHeap;
		for (size_t i = 0; i < size; i++)
		{
			if (a[i] != invalid)
			{
				MinHeap.Push(new Node(a[i]));
			}
		}
			while (MinHeap.Size()>1)
			{
				Node* L = MinHeap.Top();
				MinHeap.Pop();
				Node* R = MinHeap.Top();
				MinHeap.Pop();

				Node* root = new Node(L->_weight + R->_weight);//构建父节点
				root->_left = L;
				root->_right = R;
				L->_parent = root;
				R->_parent = root;

				MinHeap.Push(root);//放入堆中重新调整
			}
			_root = MinHeap.Top();
	}
	Node* GetNode()
	{
		return _root;
	}
private:
	Node* _root;
};

//HuffmanTreeCompress.h

#pragma once
#include "HuffmanTree.h"
#include <string>
#include <assert.h>
#include<algorithm>
typedef long long  LongType;
struct CharInfo
{
	unsigned char  _ch;   //这样定义压缩汉子是就不会出现乱码问题了
	LongType       _CharCount;   //字符出现次数
	string         _code;   //huffman编码
	CharInfo(LongType CharCount = 0)
		:_ch(0)
		, _CharCount(CharCount)
	{
	}
	CharInfo operator+(const CharInfo& c)
	{
		CharInfo tmp;
		tmp._CharCount = _CharCount + c._CharCount;
		return tmp;
	}
	bool operator != (const CharInfo c)
	{
		return _CharCount != c._CharCount;
	}
	bool operator < (const CharInfo& c)const
	{
		return _CharCount < c._CharCount;
	}
};
class FileCompress
{
public:
	FileCompress()
	{
		for (int i = 0; i < 256;i++)// 读取字符对应ASCII表,将字符存在数组下标与字符ASCLL码相等的位置
		{
			_str[i]._ch = i;
		}
	}



	void Compress(const char* filename)
	{
		assert(filename);
		FILE* fout = fopen(filename,"rb");//   使用而进制形式读,否则读不到汉字
		assert(fout);
		int ch = fgetc(fout);
		while (!feof(fout))//未读到文件结尾
		{
			_str[ch]._CharCount++;   //统计次数
			ch = fgetc(fout);        //继续向后读字符
		}
		CharInfo  invalid(0);    //定义一个非法值,当CharCount=0时就相当于一个非法值,无需根据权值构建Huffman树
		Huffman<CharInfo> hf(_str,256,invalid);  //根据字符次数构建huffman树
		string  code;
		_GetHuffmanCode(hf.GetNode(), code);
		string CompressFilename = filename;       //将编码写入压缩文件中
		CompressFilename += ".compress";
		FILE* Input = fopen(CompressFilename.c_str(),"wb");
		assert(Input);
		fseek(fout,0,SEEK_SET);
 	char Inputch = 0;   //写入文件压缩编码 
		int size = 0;
		ch = fgetc(fout);
		while (!feof(fout))
		{
			string& code = _str[ch]._code;
			for (size_t i = 0; i < code.size();++i)
			{
				 Inputch <<=1;
			 
				if (code[i]=='1')
				{
					 Inputch |= 1;
					 
				}
				++size;
				if (size == 8)
				{
					 fputc(Inputch, Input);
					 
					size = 0;
					Inputch = 0;
				}
			}
			ch = fgetc(fout);
	}
		if (size>0)
		{
		 
		 Inputch <<= 8 - size;
			 fputc(Inputch,Input);
 
		}
		fclose(fout);
		fclose(Input);
		//配置文件
		string ConfigFilename = filename;
		ConfigFilename += ".config";
		FILE* FInConfig = fopen(ConfigFilename.c_str(),"wb");
		string line;
		for (size_t i = 0; i < 256; ++i)
		{
		if (_str[i]._CharCount!=0)
		{
			line +=_str[i]._ch;
			line += ',';
			char buff[20] = { 0 };
			line += _itoa(_str[i]._CharCount, buff, 10);//转换为10进制
			line += '\n';
			fwrite(line.c_str(),1,line.size(),FInConfig);  
			line.clear();  
		}
		}
		fclose(FInConfig);
	}
	void Uncompress(const char* filename)
	{
		string ConfigFile = filename;
		ConfigFile += ".config";
		FILE* foutconfig = fopen(ConfigFile.c_str(), "rb");
		assert(foutconfig);
		string line;
		while (ReadLine(foutconfig, line))
		{
			if (line.empty())
			{
				line += '\n';
				continue;
			}
			else
			{
				unsigned char ch = line[0];
				_str[ch]._CharCount = atoi(line.substr(2).c_str());
				line.clear();
			}
		}
		CharInfo invalid(0);
		Huffman<CharInfo> hf(_str, 256, invalid);
		string uncompressfilename = filename;
		uncompressfilename += ".uncompress";
		FILE* fin = fopen(uncompressfilename.c_str(), "wb");
		assert(fin);
		string compressfilename = filename;
		compressfilename += ".compress";
		FILE* fout = fopen(compressfilename.c_str(), "rb");
		assert(fout);
		HuffmanNode<CharInfo> *root = hf.GetNode();
		LongType ChLen = root->_weight._CharCount;
		HuffmanNode<CharInfo> *cur = root;
		int pos = 7;
		int ch = fgetc(fout);
		while (ChLen)
		{
			if (ch&(1<<pos))
			{
				cur = cur->_right;
			}
			else
				cur = cur->_left;
			--pos;
			if (cur->_left==NULL&&cur->_right==NULL)
			{
				fputc(cur->_weight._ch, fin);
				cur = root;
				--ChLen;
				if (ChLen==0)
                 break;
			}
			if (pos==-1)
			{
				ch = fgetc(fout);
				pos = 7;
			}
		}
		fclose(foutconfig);
		fclose(fin);
		fclose(fout);
	}
protected:
	void _GetHuffmanCode(HuffmanNode<CharInfo>* root,string& code)
	{
   if (root==NULL)
   {
	   return;
   }
   if (root->_left==NULL&&root->_right==NULL)
   {
	   _str[root->_weight._ch]._code = code;
   }
   _GetHuffmanCode(root->_left, code + '0');
   _GetHuffmanCode(root->_right, code + '1');
	}
	bool ReadLine(FILE *fout, string& line)
	{
		int ch = fgetc(fout);
		if (feof(fout))
		{
			return false;
		}
		while (!feof(fout)&&ch!='\n')
		{
			line += ch;
			ch = fgetc(fout);
		}
		return true;
	}
protected:
	CharInfo _str[256];
};
//Heap.h

#pragma once
#include<iostream>
#include <vector>
#include <assert.h>
using  namespace std;
template<class T>
struct Less
{
	bool operator()(const T& left, const T& right)
	{
		return left < right;
	}

};
template<class T>
struct  Larger
{
	bool operator()(const T& left, const T& right)
	{
		return left > right;
	}
};
 template<class T,class Compare=Larger<T>>
 class Heap
 {
 public:
	 Heap()
	 {}
	 Heap(T* a,size_t size)
	 {
		 assert(a);
		 _a.reserve(size);
		 for (size_t i = 0; i < size;i++)
		 {
			 _a.push_back(a[i]);
		 }
		 for (size_t i = (size-2)/2; i >0;i--)
		 {
			 AdjustDown(i);
		 }
	 }
	 void Push(const T& x)
	 {
		 _a.push_back(x);
		 AdjustUp(_a.size()-1);		 
	 }
	 void Pop()
	 {
		 assert(!_a.empty());
		 swap(_a[0], _a[_a.size() - 1]);
		 _a.pop_back();
		 AdjustDown(0);
	 }
	const T& Top()
	 {
		 assert(!_a.empty());
		 return  _a[0];
	 }
	 bool Empty()
	 {
		 return _a.empty();
	 }
	 size_t  Size()
	 {
		 return _a.size();
	 }
 protected:
	 void AdjustDown(size_t root)
	 {
		 Compare  com;
		 size_t parent = root;
		 size_t  child = root * 2 + 1;    //左孩子
		 while (child<_a.size())
		 {
			 if (child + 1 < _a.size() && com(_a[child+1], _a[child]))   //右孩子存在,比较左右孩子
          {
				 ++child;
          }
			 if (com(_a[child], _a[parent]))//右孩子不存在,比较左孩子和父节点
			 {
				 std::swap(_a[parent], _a[child]);
				 parent = child;             //向下调整
				 child = parent * 2 + 1;
			 }
			 else
				 break;            
		 }
	 }
	 void  AdjustUp(size_t child)
	 {
         while (child>0)  //不是根节点
         {
			 Compare com;
			 size_t  parent = (child - 1) / 2;
			 if (com(_a[child],_a[parent]))
			 {
				 std::swap(_a[parent],_a[child]);
				 child = parent;      //向上调整
			 }
			 else
				 break;
         }
	 }
 private: 
	 vector<T> _a;
 };

 
//FileCompress.cpp

#define _CRT_SECURE_NO_WARNINGS 1
#include "HuffmanTreecompress.h"
#include<windows.h>

void test()
{
	FileCompress f;
	cout << "开始压缩" << endl;
	cout << "压缩用时:";
	 int start = GetTickCount();
	// f.Compress("test.txt");
	// f.Compress("1.mp3");
	f.Compress("2.jpg");
	int end = GetTickCount();
	cout << end - start << endl;
	cout << "开始解压" << endl;
	cout << "解缩用时:";
	start = GetTickCount();
	 //f.Uncompress("test.txt");
	//f.Uncompress("1.mp3");
	f.Uncompress("2.jpg");
	end = GetTickCount();
	cout << end - start << endl;
}
int main()
{
	test();
	system("pause");
	return 0;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值