1. 程式人生 > >哈夫曼編碼應用之實現檔案壓縮

哈夫曼編碼應用之實現檔案壓縮

背景:為了鍛鍊自己的程式碼能力,以及資料結構演算法掌握的能力,做此專案來鍛鍊自己提高自己的能力,本專案運用了C++中的知識,比如模板類,仿函式等等,還用到了資料結構中的演算法知識,比如建堆調堆、哈夫曼編碼,還用到了檔案操作的知識。總是試一次很好的訓練。

介紹一下哈夫曼編碼:

哈夫曼編碼(Huffman Coding)是一種編碼方式,哈夫曼編碼是可變字長編碼(VLC)的一種。Huffman於1952年提出一種編碼方法,該方法完全依據字元出現概率來構造異字頭的平均長 度最短的碼字,有時稱之為最佳編碼,一般就叫作Huffman編碼。


下面列出實現檔案壓縮的C++程式碼:

建堆調堆標頭檔案:Heap.h

#ifndef __HEAP_H__
#define __HEAP_H__

#include <iostream>
#include <assert.h>
#include <vector>
#include "FileCompress.h"
#include "HuffmanTree.h"

template <typename T>
struct Less
{
	bool operator()(const T& left, const T& right)const
	{
		return left < right;
	}
};

template<typename K> //模板的偏特化
struct Less<HuffmanNode<K>*>
{
	bool operator()(const HuffmanNode<K>* left, const HuffmanNode<K>* right)const
	{
		return left->_weight < right->_weight;
	}
};

//template <>
//struct Less<CharInfo>
//{
//	bool operator()(const CharInfo& left, const CharInfo& right)const
//	{
//		return left < right;
//	}
//};

template <typename T>
struct Greater
{
	bool operator()(const T& left, const T& right)const
	{
		return left > right;
	}
};

template <typename T,template<class> class Compare = Greater>
class Heap
{
	friend std::ostream& operator<<<T,Compare>(std::ostream& out, const Heap<T,Compare>& heap);
public:
	Heap();
	Heap(const T* array, size_t size);
	Heap(const Heap<T,Compare>& heap);
	Heap<T,Compare>& operator=(const Heap<T, Compare>& heap);
	~Heap();

	void Push(const T& x);
	void Pop();
	T Top()const;
	bool Empty()const;
	size_t Size()const;

protected:
	void _AdjustDown(int parent);
	void _AdjustUp(int pos);

protected:
	std::vector<T> _array;
};

//堆排序
template <typename T, template<class> class Compare = Greater>
void HeapSort(T* array, size_t size, const Compare<T>& com = Compare<T>());
//建初堆
template <typename T, template<class> class Compare = Greater>
void CrtHeap(T* array, size_t size, const Compare<T>& com = Compare<T>());
//下調
template <typename T, template<class> class Compare = Greater>
void AdjustDown(T* array, size_t size, int parent = 0, const Compare<T>& com = Compare<T>());

template <typename T, template<class> class Compare = Greater>
std::ostream& operator<<(std::ostream& out, const Heap<T, Compare>& heap);

template <typename T, template<class> class Compare = Greater>
void GetTopK(T* array, const vector<T>& money, const size_t& k, const size_t& n, const Compare<T>& com = Compare<T>());

#endif /*__HEAP_H__*/
建堆調堆實現檔案:Heap.hpp
#define _CRT_SECURE_NO_WARNINGS 1

#include "Heap.h"

template <typename T,template<class> class Compare>
Heap<T,Compare>::Heap()
{}

template <typename T,template<class> class Compare>
Heap<T,Compare>::~Heap()
{}

template <typename T,template<class> class Compare>
Heap<T,Compare>::Heap(const T* array, size_t size)
{
	this->_array.resize(size);
	for (size_t i = 0; i < size; ++i)
	{
		this->_array[i] = array[i];
	}
	for (int i = (size - 2) / 2; i >= 0; --i)
	{
		this->_AdjustDown(i);
	}
}

template <typename T,template<class> class Compare>
Heap<T,Compare>::Heap(const Heap<T,Compare>& heap)
{
	size_t size = heap.size();
	this->_array.resize(size);
	for (size_t i = 0; i < size; ++i)
	{
		this->_array[i] = heap._array[i];
	}
}

template <typename T,template<class> class Compare>
Heap<T,Compare>& Heap<T,Compare>::operator=(const Heap<T,Compare>& heap)
{
	if (this != &heap)
	{
		this->_array = heap._array;
	}
	return *this;
}

template <typename T,template<class> class Compare>
void Heap<T,Compare>::Push(const T& x)
{
	size_t size = this->_array.size();
	this->_array.push_back(x);
	this->_AdjustUp(size);
}

//Compare
template <typename T,template<class> class Compare>
void Heap<T,Compare>::_AdjustUp(int pos)
{
	assert(pos<this->_array.size());
	Compare<T> com;
	int parent = (pos - 1) / 2;
	int child = pos;
	while (parent >= 0 && com(this->_array[child], this->_array[parent]))
	{
		swap(this->_array[child], this->_array[parent]);
		child = parent;
		parent = (child - 1) / 2;
	}
}

template <typename T,template<class> class Compare>
void Heap<T,Compare>::Pop()
{
	assert(!this->_array.empty());
	size_t size = this->_array.size();
	swap(this->_array[0], this->_array[size - 1]);
	this->_array.pop_back();
	this->_AdjustDown(0);
}

//Compare
template <typename T,template<class> class Compare>
void Heap<T,Compare>::_AdjustDown(int parent)
{
	size_t child = parent * 2 + 1;
	size_t size = this->_array.size();
	Compare<T> com;
	while (child < size)
	{
		if (child + 1 < size && com(this->_array[child + 1], this->_array[child]))
		{
			++child;
		}
		if (com(this->_array[child], this->_array[parent]))
		{
			swap(this->_array[parent], this->_array[child]);
			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
			break;
		}
	}
}

template <typename T,template<class> class Compare>
T Heap<T,Compare>::Top()const
{
	assert(!this->_array.empty());
	return this->_array[0];
}

template <typename T,template<class> class Compare>
bool Heap<T,Compare>::Empty()const
{
	return this->_array.empty();
}

template <typename T,template<class> class Compare>
size_t Heap<T,Compare>::Size()const
{
	return this->_array.size();
}

template <typename T,template<class> class Compare>
std::ostream& operator<<(std::ostream& out, const Heap<T,Compare>& heap)
{
	size_t size = heap._array.size();
	for (size_t i = 0; i < size; ++i)
	{
		out << heap._array[i] << " ";
	}
	out << endl;
	return out;
}

//堆排序
//template <typename T>
//void HeapSort(T* array, size_t size)
//{
//	//建初堆
//	Heap<T,Compare> heap(array, size);
//	for (int i = size - 1; i >= 0; --i)
//	{
//		array[i] = heap.GetTop();
//		heap.Pop();
//	}
//}

template <typename T,template<class> class Compare>
void HeapSort(T* array, size_t size, const Compare<T>& com)
{
	CrtHeap(array, size, com);//建初堆
	for (int i = size - 1; i > 0; --i)
	{
		swap(array[0], array[i]); //交換頭和尾
		AdjustDown(array, i, 0, com); //使得0...i-1也為堆
	}
}

//建初堆
template <typename T, template<class> class Compare>
void CrtHeap(T* array, size_t size, const Compare<T>& com)
{
	int parent = (size - 2) / 2;
	for (int i = parent; i >= 0; --i)
	{
		AdjustDown(array, size, i, com);
	}
}
//下調 //Compare
template <typename T,template<class> class Compare>
void AdjustDown(T* array, size_t size, int parent, const Compare<T>& com)
{
	int child = parent * 2 + 1;
	while (child < (int)size)
	{
		if (child + 1 < size && com(array[child + 1], array[child]))
		{
			++child;
		}
		if (com(array[child], array[parent]))
		{
			swap(array[parent], array[child]);
			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
			break;
		}
	}
}

template <typename T, template<class> class Compare>
void GetTopK(T* array, const vector<T>& money, const size_t& k, const size_t& n, const Compare<T>& com)
{
	assert(array);
	assert(k < n);
	for (size_t i = 0; i < k; ++i)
	{
		array[i] = money[i];
	}
	//建堆
	for (int i = (k - 2) / 2; i >= 0; --i)
	{
		AdjustDown(array, k, i, com);
	}
	for (int i = k; i < n; ++i)
	{
		if (com(array[0],money[i]))
		{
			array[0] = money[i];
			AdjustDown(array, k, 0, com);
		}	
	}
}
建立哈夫曼數標頭檔案:HuffmanTree.h
#pragma once
#ifndef __HUFFMAN_TREE_H__
#define __HUFFMAN_TREE_H__

#include <iostream>

template <typename T>
struct HuffmanNode
{
	T _weight;
	HuffmanNode* _left;
	HuffmanNode* _right;
	HuffmanNode(T weight = 0) :_weight(weight), _left(NULL), _right(NULL)
	{}
	//建堆時要用
	//bool operator<(const HuffmanNode* right)
	//{
	//	return this->_weight < right->_weight;
	//}
};

template <typename T>
class HuffmanTree
{
	typedef HuffmanNode<T> Node;

public:
	HuffmanTree();
	HuffmanTree(const T* array, size_t size, int vailed = 0);
	Node* GetHuffmanNode();
	~HuffmanTree();
protected:
	static Node* _CreateHuffmanTree(const T* array, size_t size, int vailed = 0);
	static void _Clear(Node* root);
protected:
	Node* _root;
};

#endif /*__HUFFMAN_TREE_H__*/

建立哈夫曼數實現檔案:HuffmanTree.hpp

#pragma once
#ifndef __HUFFMAN_TREE_HPP__
#define __HUFFMAN_TREE_HPP__

#include "Heap.hpp"
#include "HuffmanTree.h"

template <typename T>
HuffmanTree<T>::HuffmanTree() :_root(NULL)
{}

template <typename T>
HuffmanTree<T>::HuffmanTree(const T* array, size_t size, int vailed) : _root(NULL)
{
	this->_root = _CreateHuffmanTree(array, size, vailed);
}

template <typename T>
HuffmanNode<T>* HuffmanTree<T>::_CreateHuffmanTree(const T* array, size_t size, int valid)
{
	//選最小,減小堆
	Heap<Node*, Less> heap;
	Node* parent = NULL;
	for (size_t i = 0; i < size; ++i)//往堆裡入結點
	{
		if (array[i] != valid)
		{
			heap.Push(new Node(array[i]));
		}
	}
	while (heap.Size() > 1)
	{
		Node* minFirst = heap.Top();
		heap.Pop();
		Node* minSecond = heap.Top();
		heap.Pop();
		parent = new Node(minFirst->_weight + minSecond->_weight);
		parent->_left = minFirst;
		parent->_right = minSecond;
		heap.Push(parent);
	}
	return parent;
}

template <typename T>
HuffmanTree<T>::~HuffmanTree()
{
	this->_Clear(this->_root);
}

template <typename T>
void HuffmanTree<T>::_Clear(Node* root)
{
	if (root)
	{
		_Clear(root->_left);
		_Clear(root->_right);
		delete root;
	}
}

template <typename T>
HuffmanNode<T>* HuffmanTree<T>::GetHuffmanNode()
{
	return this->_root;
}

#endif /*__HUFFMAN_TREE_HPP__*/

檔案壓縮標頭檔案:FileCompress.h
#pragma once 
#ifndef __HUFFMAN_CODE_H__
#define __HUFFMAN_CODE_H__

#include <iostream>
#include <vector>
#include <string>
#include "HuffmanTree.h"

using namespace std;

typedef unsigned long long TypeLong;

struct CharInfo
{
	unsigned char _ch; //字元
	TypeLong _count;//出現次數
	string _code;//Huffman編碼
	CharInfo(TypeLong count = 0) :_ch(0), _count(count)
	{}
	bool operator!=(const CharInfo& info)const
	{
		return this->_count != info._count;
	}
	bool operator<(const CharInfo& info)const 
	{
		return this->_count < info._count;
	}
	CharInfo operator+(const CharInfo& info)const
	{
		return CharInfo(this->_count + info._count);
	}
};

class FileCompress
{
public:
	FileCompress();
	void CompressHuffCode(const char* filename);
	void UnCompressHuffCode(const char* filename);
	void PrintCode()const;

protected:
	static void GenerateHuffmanCode(HuffmanNode<CharInfo>* root, FileCompress& file, string& code);
	
protected:
	CharInfo _info[256];

};

#endif /*__HUFFMAN_CODE_H__*/

檔案壓縮實現檔案:FileCompreess.cpp
#define _CRT_SECURE_NO_WARNINGS 1


#include <assert.h>
#include "FileCompress.h"
#include <io.h>
#include <direct.h>


#define __DEBUG_COUT__


FileCompress::FileCompress()
{
<span style="white-space:pre">	</span>size_t size = sizeof(this->_info) / sizeof(this->_info[0]);
<span style="white-space:pre">	</span>for (size_t i = 0; i < size; ++i)
<span style="white-space:pre">	</span>{
<span style="white-space:pre">		</span>this->_info[i]._ch = i;
<span style="white-space:pre">		</span>this->_info[i]._count = 0;
<span style="white-space:pre">	</span>}
}


void FileCompress::CompressHuffCode(const char* filename)
{
<span style="white-space:pre">	</span>assert(filename);
<span style="white-space:pre">	</span>FILE* fOut = fopen(filename, "rb");
<span style="white-space:pre">	</span>assert(fOut);
<span style="white-space:pre">	</span>//統計字元出現的次數
<span style="white-space:pre">	</span>unsigned char ch = fgetc(fOut);
<span style="white-space:pre">	</span>while (!feof(fOut))
<span style="white-space:pre">	</span>{
<span style="white-space:pre">		</span>++this->_info[(unsigned char)ch]._count;
<span style="white-space:pre">		</span>ch = fgetc(fOut);
<span style="white-space:pre">	</span>}


<span style="white-space:pre">	</span>fseek(fOut, 0, SEEK_SET);
<span style="white-space:pre">	</span>//建立哈夫曼樹
<span style="white-space:pre">	</span>HuffmanTree<CharInfo> huffTree(this->_info, sizeof(this->_info) / sizeof(this->_info[0]), 0);


<span style="white-space:pre">	</span>//生成哈夫曼編碼
<span style="white-space:pre">	</span>string code;
<span style="white-space:pre">	</span>HuffmanNode<CharInfo>* root = huffTree.GetHuffmanNode();
<span style="white-space:pre">	</span>GenerateHuffmanCode(root, *this, code);


<span style="white-space:pre">	</span>//生成壓縮檔名及配置配置檔名
<span style="white-space:pre">	</span>string fileNewName = (string)filename; 


<span style="white-space:pre">	</span>size_t last_ = fileNewName.find_last_of('.');
<span style="white-space:pre">	</span>size_t name_ = fileNewName.find_last_of('\\');//檔名
<span style="white-space:pre">	</span>if (last_ < fileNewName.size())
<span style="white-space:pre">	</span>{
<span style="white-space:pre">		</span>fileNewName.erase(last_);
<span style="white-space:pre">	</span>}


<span style="white-space:pre">	</span>char file[10], type[10];
<span style="white-space:pre">	</span>strcpy(file, filename + name_ + 1);  //檔名
<span style="white-space:pre">	</span>strcpy(type, filename + last_ );  //檔案型別


<span style="white-space:pre">	</span>fileNewName += "_rar\\";


<span style="white-space:pre">	</span>char *fileName = (char *)fileNewName.c_str(), *tag, path[1000];
<span style="white-space:pre">	</span>strcpy(path, fileName);
<span style="white-space:pre">	</span>int a = 0;
<span style="white-space:pre">	</span>for (tag = fileName; *tag; tag++)
<span style="white-space:pre">	</span>{
<span style="white-space:pre">		</span>if (*tag == '\\')
<span style="white-space:pre">		</span>{
<span style="white-space:pre">			</span>a = strlen(fileName) - strlen(tag);
<span style="white-space:pre">		</span>}
<span style="white-space:pre">	</span>}
<span style="white-space:pre">	</span>path[a] = NULL;
<span style="white-space:pre">	</span>char filePath[1000];


<span style="white-space:pre">	</span>sprintf(filePath, "md %s", path);
<span style="white-space:pre">	</span>system(filePath);
<span style="white-space:pre">	</span>fileNewName += file;


<span style="white-space:pre">	</span>string fileInName = fileNewName;//壓縮檔名
<span style="white-space:pre">	</span>string fileConfig = fileInName;//配置檔名


<span style="white-space:pre">	</span>last_ = fileNewName.find_last_of('.');
<span style="white-space:pre">	</span>if (last_ < fileNewName.size())
<span style="white-space:pre">	</span>{
<span style="white-space:pre">		</span>fileInName.erase(last_);
<span style="white-space:pre">		</span>fileConfig.erase(last_);
<span style="white-space:pre">	</span>}
<span style="white-space:pre">	</span>
<span style="white-space:pre">	</span>fileInName += ".huff";
<span style="white-space:pre">	</span>fileConfig += ".config";


<span style="white-space:pre">	</span>string tmp;


<span style="white-space:pre">	</span>//生成壓縮配置檔案
<span style="white-space:pre">	</span>FILE* fConfig = fopen(fileConfig.c_str(), "wb");
<span style="white-space:pre">	</span>char *tyone = type;
<span style="white-space:pre">	</span>for (int i = 0; i < 10; i++)
<span style="white-space:pre">	</span>{
<span style="white-space:pre">		</span>fputc(*tyone,fConfig);
<span style="white-space:pre">		</span>tyone++;
<span style="white-space:pre">	</span>}
<span style="white-space:pre">	</span>char buff[20] = { 0 };
<span style="white-space:pre">	</span>for (size_t i = 0; i < sizeof(this->_info) / sizeof(this->_info[0]); ++i)
<span style="white-space:pre">	</span>{
<span style="white-space:pre">		</span>tmp.clear();
<span style="white-space:pre">		</span>if (this->_info[i]._count != 0)
<span style="white-space:pre">		</span>{
<span style="white-space:pre">			</span>tmp += this->_info[i]._ch;
<span style="white-space:pre">			</span>tmp += ':';
<span style="white-space:pre">			</span>tmp += (string)_itoa((this->_info[i]._count), buff, 10);
<span style="white-space:pre">			</span>tmp += '\n';
<span style="white-space:pre">			</span>fputs(tmp.c_str(), fConfig);<span style="white-space:pre">		</span>
<span style="white-space:pre">		</span>}
<span style="white-space:pre">	</span>}






<span style="white-space:pre">	</span>//對檔案進行壓縮
<span style="white-space:pre">	</span>FILE* fIn = fopen(fileInName.c_str(), "wb");
<span style="white-space:pre">	</span>assert(fIn);


<span style="white-space:pre">	</span>int pos = 0;
<span style="white-space:pre">	</span>unsigned char putch = 0;
<span style="white-space:pre">	</span>ch = fgetc(fOut);
<span style="white-space:pre">	</span>while (!feof(fOut))
<span style="white-space:pre">	</span>{
<span style="white-space:pre">		</span>tmp = this->_info[(unsigned char)ch]._code;
<span style="white-space:pre">		</span>for (size_t i = 0; i < tmp.size(); ++i)
<span style="white-space:pre">		</span>{
<span style="white-space:pre">			</span>putch <<= 1;
<span style="white-space:pre">			</span>putch |= (tmp[i] - '0');
<span style="white-space:pre">			</span>if (++pos == 8)
<span style="white-space:pre">			</span>{
<span style="white-space:pre">				</span>fputc(putch, fIn);
<span style="white-space:pre">				</span>pos = 0;
<span style="white-space:pre">				</span>putch = 0;
<span style="white-space:pre">			</span>}
<span style="white-space:pre">		</span>}
<span style="white-space:pre">		</span>ch = fgetc(fOut);
<span style="white-space:pre">	</span>}
<span style="white-space:pre">	</span>if (pos > 0)
<span style="white-space:pre">	</span>{
<span style="white-space:pre">		</span>putch <<= (8 - pos);
<span style="white-space:pre">		</span>fputc(putch, fIn);
<span style="white-space:pre">	</span>}


<span style="white-space:pre">	</span>fclose(fOut);
<span style="white-space:pre">	</span>fclose(fIn);
<span style="white-space:pre">	</span>fclose(fConfig);
}


void FileCompress::GenerateHuffmanCode(HuffmanNode<CharInfo>* root, FileCompress& file, string& code)
{
<span style="white-space:pre">	</span>if (root == NULL)
<span style="white-space:pre">	</span>{
<span style="white-space:pre">		</span>return;
<span style="white-space:pre">	</span>}
<span style="white-space:pre">	</span>if (root->_left == NULL && root->_right == NULL)
<span style="white-space:pre">	</span>{
<span style="white-space:pre">		</span>file._info[root->_weight._ch]._code = code;
<span style="white-space:pre">		</span>return;
<span style="white-space:pre">	</span>}
<span style="white-space:pre">	</span>code.push_back('0'); 
<span style="white-space:pre">	</span>GenerateHuffmanCode(root->_left, file, code);
<span style="white-space:pre">	</span>code.pop_back(); 
<span style="white-space:pre">	</span>code.push_back('1');
<span style="white-space:pre">	</span>GenerateHuffmanCode(root->_right, file, code);
<span style="white-space:pre">	</span>code.pop_back();
}


void FileCompress::UnCompressHuffCode(const char* filename)
{
<span style="white-space:pre">	</span>assert(filename);
<span style="white-space:pre">	</span>FILE* fOut = fopen(filename, "rb");
<span style="white-space:pre">	</span>assert(fOut);
<span style="white-space:pre">	</span>//讀取檔案,
<span style="white-space:pre">	</span>string fileConfig = (string)filename;
<span style="white-space:pre">	</span>string fileNewName = (string)filename;
<span style="white-space:pre">	</span>string fileInName = fileConfig;
<span style="white-space:pre">	</span>size_t last_ = fileInName.find_last_of('.');
<span style="white-space:pre">	</span>size_t name_ = fileNewName.find_last_of('\\');
<span style="white-space:pre">	</span>if (name_ < fileNewName.size())
<span style="white-space:pre">	</span>{
<span style="white-space:pre">		</span>fileConfig.erase(last_);
<span style="white-space:pre">		</span>fileNewName.erase(name_);
<span style="white-space:pre">	</span>}


<span style="white-space:pre">	</span>char file[10];
<span style="white-space:pre">	</span>strcpy(file, fileConfig.c_str() + name_ + 1);//檔名


<span style="white-space:pre">	</span>name_ = fileNewName.find_last_of('\\');
<span style="white-space:pre">	</span>if (name_ < fileInName.size())
<span style="white-space:pre">	</span>{
<span style="white-space:pre">		</span>fileInName.erase(name_+1);
<span style="white-space:pre">	</span>}


<span style="white-space:pre">	</span>fileInName += file;  //彌補檔名


<span style="white-space:pre">	</span>fileConfig += ".config";


<span style="white-space:pre">	</span>FILE* fConfig = fopen(fileConfig.c_str(), "rb");
<span style="white-space:pre">	</span>assert(fConfig);


<span style="white-space:pre">	</span>//修改_count,注意\n,有可能代表字元,有可能是行結束標誌
<span style="white-space:pre">	</span>char buff[20] = { 0 }, type[10] = { 0 };
<span style="white-space:pre">	</span>char *tyone = type;
<span style="white-space:pre">	</span>for (int i = 0; i < 10; i++)
<span style="white-space:pre">	</span>{
<span style="white-space:pre">		</span>*tyone = fgetc(fConfig);
<span style="white-space:pre">		</span>tyone++;
<span style="white-space:pre">	</span>}
<span style="white-space:pre">	</span>unsigned char ch = fgetc(fConfig);
<span style="white-space:pre">	</span>while (!feof(fConfig))
<span style="white-space:pre">	</span>{
<span style="white-space:pre">		</span>fgetc(fConfig);//讀取冒號
<span style="white-space:pre">		</span>fgets(buff, 20, fConfig);
<span style="white-space:pre">		</span>this->_info[ch]._count = (TypeLong)atoi((buff));
<span style="white-space:pre">		</span>ch = fgetc(fConfig);
<span style="white-space:pre">	</span>}




<span style="white-space:pre">	</span>fileInName += "_unrar";
<span style="white-space:pre">	</span>fileInName += type;


<span style="white-space:pre">	</span>FILE* fIn = fopen(fileInName.c_str(), "wb");
<span style="white-space:pre">	</span>assert(fIn);
<span style="white-space:pre">	</span>//重建哈夫曼樹
<span style="white-space:pre">	</span>HuffmanTree<CharInfo> tree(this->_info, sizeof(this->_info) / sizeof(this->_info[0]), 0);
<span style="white-space:pre">	</span>HuffmanNode<CharInfo>* root = tree.GetHuffmanNode();
<span style="white-space:pre">	</span>HuffmanNode<CharInfo>* cur = root;
<span style="white-space:pre">	</span>TypeLong countSum = root->_weight._count; //記錄字元的總個數控制結束
<span style="white-space:pre">	</span>ch = fgetc(fOut);
<span style="white-space:pre">	</span>int pos = 7;
<span style="white-space:pre">	</span>while (countSum > 0)
<span style="white-space:pre">	</span>{
<span style="white-space:pre">		</span>while (pos >= 0)
<span style="white-space:pre">		</span>{
<span style="white-space:pre">			</span>if ((ch & (1 << pos)) == 0) //向左走
<span style="white-space:pre">			</span>{
<span style="white-space:pre">				</span>cur = cur->_left;
<span style="white-space:pre">			</span>}
<span style="white-space:pre">			</span>else
<span style="white-space:pre">			</span>{
<span style="white-space:pre">				</span>cur = cur->_right;
<span style="white-space:pre">			</span>}
<span style="white-space:pre">			</span>if (cur->_left == NULL && cur->_right == NULL)
<span style="white-space:pre">			</span>{
<span style="white-space:pre">				</span>fputc(cur->_weight._ch, fIn);


#ifndef __DEBUG_COUT__
<span style="white-space:pre">				</span>cout << cur->_weight._ch;
#endif /*__DEBUG_COUT__*/


<span style="white-space:pre">				</span>if (--countSum == 0)//將沒有寫的字元的次數減1
<span style="white-space:pre">					</span>break;
<span style="white-space:pre">				</span>cur = root;
<span style="white-space:pre">			</span>}
<span style="white-space:pre">			</span>--pos;
<span style="white-space:pre">		</span>}
<span style="white-space:pre">		</span>pos = 7;
<span style="white-space:pre">		</span>ch = fgetc(fOut);
<span style="white-space:pre">	</span>}
<span style="white-space:pre">	</span>fclose(fIn);
<span style="white-space:pre">	</span>fclose(fOut);
<span style="white-space:pre">	</span>fclose(fConfig);
}


void FileCompress::PrintCode()const
{
<span style="white-space:pre">	</span>for (int i = 0; i < 256; ++i)
<span style="white-space:pre">	</span>{
<span style="white-space:pre">		</span>if (this->_info[i]._count != 0)
<span style="white-space:pre">		</span>{
<span style="white-space:pre">			</span>cout << this->_info[i]._ch << ":>" << this->_info[i]._code << endl;
<span style="white-space:pre">		</span>}
<span style="white-space:pre">	</span>}
}


測試程式碼:壓縮測試函式,放在主函式裡
void test()
{
	string filename = "C:\\Users\\小明\\Desktop\\input.txt";
	cout << "壓縮時間";
	MyTimer timer;
	timer.Start();
	////////////////////////////////

	FileCompress fc;
	fc.CompressHuffCode(filename.c_str());

	/////////////////////////////////
	timer.Stop();
	timer.showTime();

}
測試程式碼:解壓縮測試函式,放在主函式裡
void untest()
{
	string filename = "C:\\Users\\小明\\Desktop\\input_rar\\input.huff";
	cout << "解壓時間";
	MyTimer timer;
	timer.Start();
	////////////////////////////////

	FileCompress unfc;
	unfc.UnCompressHuffCode(filename.c_str());

	/////////////////////////////////
	timer.Stop();
	timer.showTime();
	
}
主函式:test.cpp
#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
using namespace std;

#include "HuffmanTree.hpp"
#include "FileCompress.h"
#include "FileCompress.cpp"

#include "TimeCheck.h"


void test()
{
	string filename = "C:\\Users\\小明\\Desktop\\input.txt";   //需要壓縮的檔案
	cout << "壓縮時間";
	MyTimer timer;
	timer.Start();
	////////////////////////////////

	FileCompress fc;
	fc.CompressHuffCode(filename.c_str());

	/////////////////////////////////
	timer.Stop();
	timer.showTime();

}

void untest()
{
	string filename = "C:\\Users\\小明\\Desktop\\input_rar\\input.huff";  //需要解壓縮的檔名
	cout << "解壓時間";
	MyTimer timer;
	timer.Start();
	////////////////////////////////

	FileCompress unfc;
	unfc.UnCompressHuffCode(filename.c_str());

	/////////////////////////////////
	timer.Stop();
	timer.showTime();
	
}

int main()
{ 

	test();
	untest();

	system("pause");
	return 0;
}

現在測試的是我桌面上的一個檔案:檔名為:input.txt

壓縮過程

壓縮和解壓縮之後桌面顯示:

解壓縮檔案:input_Com.txt

本專案特點:將壓縮後的檔案,以及配置檔案新建立了一個資料夾,放在資料夾中,這樣美觀,易識別。

程式碼中還有很多不足,有些問題也未解決,歡迎各位批評指正!!!  我也會子啊後續努力中繼續新增功能!