데이터 구조 - 파일 압축 (하프 만 인 코딩 으로 구현)

9435 단어 데이터 구조
파일 압축 원리: 우선 파일 압축 은 HuffmaCode 를 통 해 이 루어 집 니 다. 전체적인 사고방식 은 파일 읽 기 를 통 해 문자 가 나타 나 는 빈 도 를 가 져 옵 니 다. 문자 가 나타 나 는 빈 도 를 통 해 HuffmanTree 를 구축 할 수 있 습 니 다. 각 파일 에 나타 나 는 문 자 는 HuffmanTree 를 통 해 HuffmanCode 를 가 져 옵 니 다. 이로써 파일 에 있 는 문 자 를 HuffmanTree 와 같은 인 코딩 을 가 져 오고 압축 파일 에 기록 합 니 다.파일 압축 을 완료 합 니 다.왜 Huff man Code 를 통 해 파일 의 압축 을 실현 할 수 있 습 니까?원인: 1. 파일 마다 문자 종류 가 제한 되 어 있 습 니 다.2. 문자 마다 나타 나 는 횟수 가 많 을 수 있 습 니 다.3. Huff man Tree 구조의 특징: Huff man Tree 는 뿌리 노드 에 가 까 울 수록 잎 노드 의 가중치 가 크 고 경로 가 짧다.파일 에 있 는 문자 가 많이 반 복 될 수록 뿌리 노드 에 가 까 운 잎 노드 의 가중치 가 크 고 이 문자 들 의 경로 가 가장 짧 기 때문에 Huff man Code 는 짧 을 수록 이 문자 들 이 많은 상황 에서 압축 률 이 높다.어떻게 Huff man Code 를 생 성 합 니까?1. Huff man Code 가 발생 하 는 조건 은 Huff man Tree 를 구축 하고 Huff man Tree 를 구축 하 는 노드 에서 가중치 가 가장 작고 가중치 가 작은 노드 를 선택 하 는 것 이다.그래서 좌우 자 수 를 형성 하고 좌우 자 수의 가중치 를 더 해 아버지 노드 의 가중치 로 한다.허 프 맨 트 리 를 구축 하 는 노드 집합 에 아버지 노드 를 넣 기;집합 에 한 노드 가 남 을 때 까지 최소, 차 소 를 계속 선택 하 십시오. 이 노드 는 뿌리 노드 입 니 다.2. Huff man Tree 의 모든 잎 노드 를 옮 겨 다 니 는 경 로 를 통 해 파일 마다 나타 나 는 문자 의 Huff man Code 를 가 져 옵 니 다.이러한 압축 원 리 를 이해 한 후에 우 리 는 어떻게 파일 압축 을 실현 해 야 합 니까?파일 압축 프로 세 스: 1. 파일 을 읽 고 문자 발생 횟수 를 통계 합 니 다.2. 통 계 된 문자 출현 횟수 를 통 해 Huff mantree 를 구축한다.3. 허 프 맨 코드 가 져 오기.4. 설정 정보 (문자 마다 나타 나 는 횟수, 압축 을 풀 때 Huff mantree 재 구성) 와 같이 쓰 십시오.5. 파일 을 읽 고 파일 에 나타 난 문자 의 Huffman Code 를 압축 파일 에 순서대로 압축 합 니 다.파일 압축 해제 프로 세 스: 1. 설정 정 보 를 읽 습 니 다.2. 정 보 를 읽 고 Huff mantree 를 재 구성 합 니 다.3. Huff mantree 를 인 코딩 해서 압축 파일 에 쓰 는 문 자 를 가 져 옵 니 다.Huff man Tree 구축 에 사용 되 는 기술 1. 더미: 작은 더 미 를 통 해 최소 값 과 작은 값 을 선택 합 니 다.(앞 에 강의 가 쌓 인 블 로그 가 있다).2. 모방 함수: 더미 에 모방 함 수 를 사 용 했 습 니 다 (모방 함 수 를 통 해 CharInfo 의 가중치 크기 를 비교 하여 쌓 습 니 다).3. Huff man Code: Huff man Tree 의 모든 정 보 는 잎 노드 에 있 고 모든 잎 노드 는 유일한 확실한 경로 (뿌리 노드 에서 잎 노드 까지 의 경로) 가 있 기 때 문 입 니 다. 즉, 이 경 로 는 Huff man Code 이 고 모든 잎 노드 는 유일한 문자 에 대응 합 니 다.4. string 클래스: HuffmanCode 를 저장 합 니 다.파일 압축 의 일부 세부 사항: 파일 에 있 는 모든 문자 의 출현 횟수 를 통계 합 니 다.Ascall 코드 문 자 는 모두 255 개 입 니 다. 앞의 128 글자 만 표시 할 수 있 기 때문에 문자 변 수 를 정의 할 때 반드시 기호 가 없 는 변수 unsigned char ch 로 정의 해 야 합 니 다. 이것 은 ch 가 파일 을 읽 을 수 없 는 끝 표지 이기 때문에 우 리 는 함수 feof 로 파일 의 끝 표지 EOF 를 대체 할 수 있 습 니 다.가장 중요 한 것 은 파일 을 여 는 방식 입 니 다. 바 이 너 리 형식 으로 열 어야 합 니 다. 그렇지 않 으 면 한자 문 자 를 읽 지 못 하고 어 지 러 운 코드 가 발생 합 니 다.이 255 자 는 해시 맵 으로 저장 합 니 다info [256] 배열 중.배열 아래 에 표 시 된 모든 문 자 를 표시 하여 문자 가 나타 나 는 횟수 와 대응 하도록 합 니 다.배열 요소 에 문자 인 코딩 과 문자 에 대응 하 는 횟수 를 저장 합 니 다.우리 가 밧줄 을 끄 는 데 편리 하 다.파일 압축 각 부분 헤더 파일 Heap. h:
#pragma once
#include
#include
#include
#include
using namespace std;

template
struct Less
{
	bool operator()(const T& l, const T& r)
	{
		return l < r;
	}
};
template
struct Great
{
	bool operator()(const T& l, const T& r)
	{
		return l>r;
	}
};

template>
class Heap
{
public:
	Heap()
	{}
	Heap(T* a, size_t size)
	{
		_array.reserve(size);
		for (size_t i = 0; i < size; i++)
		{
			_array.push_back(a[i]);
		}
		//  ,         ,      
		for (int i = (size - 2) / 2; i >= 0; --i)
		{
			AdjustDown(i);
		}
	}
	void Push(const T&data)
	{
		_array.push_back(data);
		AdjustUp(_array.size() - 1);
	}
	void Pop()
	{
		if (!_array.empty())
		{
			swap(_array[0], _array[_array.size() - 1]);
			_array.pop_back();
			AdjustDown(0);
		}
	}
	const T& Top()
	{
		assert(!_array.empty());
		return _array[0];
	}
	bool Empty()
	{
		return _array.empty();
	}
	size_t Size()
	{
		return _array.size();
	}
private:
	void AdjustUp(int root)
	{
		int child = root;
		int parent = (child - 1) / 2;
		compare com;
		while (parent >= 0)
		{
			if (com(_array[child], _array[parent]))
			{
				swap(_array[child], _array[parent]);
				child = parent;
				parent = (child - 1) / 2;
			}
			else
				break;
		}
	}
	void AdjustDown(int root)
	{
		size_t parent = root;
		size_t child = root * 2 + 1;
		compare com;
		while (child < _array.size())
		{
			if (child + 1 < _array.size() && com(_array[child + 1], _array[child]))
				child++;
			if (com(_array[child], _array[parent]))
			{
				swap(_array[child], _array[parent]);
				parent = child;
				child = parent * 2 + 1;
			}
			else
			{
				break;
			}
		}
	}
	vector _array;
};

HuffmanTree.h:
#pragma once
#include"Heap.h"
template
struct HuffmanNode
{
	HuffmanNode* _left;
	HuffmanNode* _right;
	HuffmanNode* _parent;
	W _w;//  
	HuffmanNode(const W& w)
		:_left(NULL)
		, _right(NULL)
		, _parent(NULL)
		, _w(w)
	{}
};

template
class HuffmanTree
{
public:
	typedef HuffmanNode Node;//HuffmanNode    Node
	HuffmanTree()
	{
		root = NULL;
	}
	HuffmanTree(W* w, size_t size, const W& invalid)//  huffmantree   w,     size,    
	{
		//1.   ,      、     Huffmantree
		//         
		struct NodeCompare
		{
			bool operator()(Node* l,  Node* r)
			{
				return l->_w < r->_w;
			}
		};
		//2.  
		Heap minheap;
		for (size_t i = 0; i < size; i++)
		{
			if (w[i] != invalid)
			{
				minheap.Push(new Node(w[i]));
			}
		}
		//3.  Huffmantree
		while (minheap.Size()>1)
		{
			Node* left = minheap.Top();//   
			minheap.Pop();
			Node* right = minheap.Top();//   
			minheap.Pop();
			Node* parent = new Node(left->_w + right->_w);
			parent->_left = left;
			parent->_right = right;
			left->_parent = parent;
			right->_parent = parent;
			minheap.Push(parent);
		}
		root = minheap.Top();
	}
	Node* GetRoot()
	{
		return root;
	}
private:
	//                  
	HuffmanTree(const HuffmanTree& tree);
	HuffmanTree& operator=(const HuffmanTree& tree);
	Node* root;
};

FileCompress.h
#pragma once

#include
using namespace std;

#include
#include

#include"Huffman.h"

//      ,     HuffmanTree
struct CharInfo
{
	char _ch;
	string _code;//  Huffman  
	long long _count;//ch     
	bool operator !=(const CharInfo& info)
	{
		return _count!= info._count;
	}
	bool operator  Node;
	//    
	struct ConfInfo
	{
		char _ch;
		long long _count;
	};
public:
	//         _info[]
	FileCompress()
	{
		for (int i = 0; i < 256; i++)
		{
			_info[i]._ch = i;
			_info[i]._count = 0;
		}
	}
	//    
	void Compress(char* file)
	{
		//1.    ,      
		FILE* fout = fopen(file, "rb");
		assert(fout);
		char ch = getc(fout);
		while (!feof(fout))
		{
			_info[(unsigned char)ch]._count++;
			ch = getc(fout);
		}
		//2.  HuffmanTree
		CharInfo invalid;
		invalid._count = 0;
		HuffmanTree tree(_info, 256, invalid);

		//3.  Huffman  
		string code;
		Node* root = tree.GetRoot();
		GetHuffmanCode(root, code);
		//4.    ,      ;         HuffmanTree
		string Comfile = file;
		Comfile += ".Compress";
		FILE* fin = fopen(Comfile.c_str(), "wb");
		ConfInfo info;
		for (int i = 0; i < 256; i++)
		{
			if (_info[i]._count != 0)
			{
				info._ch = _info[i]._ch;
				info._count = _info[i]._count;
				fwrite(&info, sizeof(ConfInfo), 1, fin);
			}
		}
		
		//              
		info._count = 0;
		fwrite(&info, sizeof(ConfInfo), 1, fin);
		//5.  
		fseek(fout, 0, SEEK_SET);
		char value = 0;
		int pos = 0;
		Node* cur = root;
		ch = fgetc(fout);
		while (!feof(fout))
		{
			string code = _info[(unsigned char)ch]._code;
			for (int i = 0; i < code.size(); i++)
			{
				if (code[i] == '1')
					value |= (1 << pos);
				else if (code[i] == '0')
					value &= ~(1 << pos);
				else
					assert(false);
				pos++;
				if (pos == 8)
				{
					putc(value, fin);
					pos = 0;
					value = 0;
				}
			}
			ch = getc(fout);
		}
		if (pos != 0)
			putc(value, fin);
		//       
		fclose(fout);
		fclose(fin);
	}
	void UnCompress(char* file)
	{
		//1.      
		assert(file);
		FILE* fout = fopen(file, "rb");
		assert(fout);
		while (1)
		{
			ConfInfo info;
			fread(&info, sizeof(ConfInfo), 1, fout);
			if (info._count == 0)
				break;
			_info[(unsigned char)info._ch]._count = info._count;
		}
		//2.  huffmanTree
		CharInfo invalid;
		invalid._count = 0;
		HuffmanTree tree(_info,256,invalid);
		//3.   
		string UnCompress = file;
		size_t find = UnCompress.rfind('.');
		UnCompress.erase(find, UnCompress.size() - find);
		UnCompress += ".UnCompress";
		FILE* fin = fopen(UnCompress.c_str(), "wb");
		Node* root = tree.GetRoot();
		Node* cur = root;
		long long count = root->_w._count;
		char value = fgetc(fout);
		while (!feof(fout))
		{
			for (size_t pos = 0; pos < 8; pos++)
			{
				if (value & (1 << pos))
					cur = cur->_left;
				else
					cur = cur->_right;
				if (cur->_left == NULL && cur->_right == NULL)
				{
					putc(cur->_w._ch, fin);
					cur = root;
					count--;
					if (count == 0)
						break;
				}
			}
			value = getc(fout);
		}
		fclose(fout);
		fclose(fin);
	}
private:
	void GetHuffmanCode(Node* root, string code)//  HuffmanCode
	{
		if (root == NULL)
			return;
		if (root->_left == NULL && root->_right == NULL)
		{
			_info[(unsigned char)root->_w._ch]._code = code;
			return;
		}
		GetHuffmanCode(root->_left, code + '1');
		GetHuffmanCode(root->_right, code + '0');
	}
	CharInfo _info[256];
};

좋은 웹페이지 즐겨찾기