哈夫曼树(Huffman)及其无损压缩实现

      大家好!过完新年后,在宿舍闲着蛋疼,就把上学期无法实现的哈夫曼树的压缩及其解压实现一下了。至于怎么压缩各种格式的文件,现在还没有找到实现方法。

以下是代码实现:

//Huffman_H.h

#ifndef Huffman_H

#define Huffman_H



#include <string>

#include <fstream>

#include <queue>

#include <vector>

using namespace std;



const int MAX_SIZE = 256;   //含有256个ACSII码

struct huffman_node

{

	char id;

	int freq;

	string code;

	huffman_node* left;

	huffman_node* right;

	huffman_node* parent;

	//默认的构造函数

	huffman_node(char ch = '\0',string s = "", int cou = 0,huffman_node* lef = NULL, huffman_node* rig = NULL,huffman_node* par = NULL):

	id(ch),code(s),freq(cou),left(lef),right(rig),parent(par){}

};

typedef huffman_node* node_ptr;



class Huffman

{

protected:

	node_ptr node_array[MAX_SIZE];

	fstream in_file;

	fstream out_file;

	ofstream decompress_file;    //解压使用的文件输入输出流

	node_ptr child;

	node_ptr parent;

	char id;

	int decodingnum;    //记录解码时有多少种不同的字符

	string in_file_name;

	string out_file_name;

	class compare

	{

	public:

		bool operator()(const node_ptr& c1,const node_ptr& c2) const

		{

			return (*c1).freq > (*c2).freq;

		}

	};

	//用于比较优先队列中元素间的顺序

	priority_queue<node_ptr,vector<node_ptr>,compare > pq;

	//根据输入文件构造包含字符及其频率的数组

	void create_node_array();



public:

	node_ptr root;

	//根据输入和输出流初始化对象

	Huffman(string s1,string s2);



	//构造优先队列

	void create_pq();



	//构造Huffman树

	void create_huffman_tree();



	//计算Huffman编码

	void calculate_huffman_codes(node_ptr & root);



	//将Huffman编码和编码后的文本存入文件

	void save_to_file();



	//将压缩好的文件解压回去

	void decompress_to_file();

};



#endif

	

 

//Huffman.cpp

#include "Huffman_H.h"

#include <iostream>

#include <fstream>



void Huffman::create_node_array()

{

	unsigned char ch;   //定义读取的字节单位

	int num = 0;

	in_file.open(in_file_name,ios::in | ios::binary);   //使用二进制读入文件即可对所有的文件格式进行操作

	in_file.read((char *)&ch,sizeof(char));        //一个字节一个字节的读入,并存储相应的字符极其权重

	while(!in_file.eof())

	{

		num = int(ch);

		if(node_array[num]->freq == 0)

		{

			node_array[num]->id = ch;

		}

		node_array[num]->freq++;

		in_file.read( (char *)&ch, sizeof(char));

	}

	in_file.close();

//将字符极其权重存入优先队列中进行排序

}



//构造函数,主要负责初始化工作

Huffman::Huffman(string s1,string s2)

{

	in_file_name = s1;

	out_file_name = s2;

	root = NULL;

	parent = NULL;

	child = NULL;

	decodingnum = 0;

	int i;

	//这里值得注意,因为要给256个哈夫曼树的结点划分空间

	for(i = 0;i < MAX_SIZE;i++)

	{

		node_array[i] = new huffman_node();

	}

}



//构造优先队列

void Huffman::create_pq()

{

	create_node_array();

	int i;

	for(i = 0; i < MAX_SIZE;i++)

	{

		if(node_array[i]->freq > 0)

		{

			decodingnum++;

			pq.push(node_array[i]);

		}

	}

}



//构造Huffman树

void Huffman::create_huffman_tree()

{

	while(pq.size() > 1)     ////在队列中的数在一个以上时进行节点合并构建Huffman树

	{

		node_ptr h1,h2;

		h1 = pq.top();

		pq.pop();

		h2 = pq.top();

		pq.pop();

		node_ptr h = new huffman_node();

		h->freq = h1->freq + h2->freq;

		h->left = h1;

		h->right = h2;

		h1->parent = h;

		h2->parent = h;

		pq.push(h);   //按照huffman算法,再把它放回优先队列里面

	}

	root = pq.top();

	root->parent = NULL;

}



//计算Huffman编码

void Huffman::calculate_huffman_codes(node_ptr & root)

{

	//若哈夫曼树为空,则不操作.

	if(root == NULL)

		;

	else

	{

		if(root->left != NULL)

		{

			root->left->code = root->code + '0';

			calculate_huffman_codes(root->left);

		}

		if(root->right != NULL)

		{

			root->right->code = root->code + '1';

			calculate_huffman_codes(root->right);

		}

	}

}



//将Huffman编码和编码后的文本存入文件

void Huffman::save_to_file()

{

	int bytenum = 0;       //记录字节的位数,每8位刷新一次

	unsigned char temp,ch = 0;

	int i;

	out_file.open(out_file_name,ios::out|ios::binary);    //将编码的情况写入压缩文件里

	out_file.write((char*)&decodingnum,sizeof(char));    //将编码情况先存入压缩文件中以便在解压时使用,有多少种不同类型的字符

	for(i = 0;i < MAX_SIZE;i++)

	{

		if(node_array[i]->freq != 0)

		{ 

			//将字符和频率逐个字符读入

			out_file.write((char *)&node_array[i]->id,sizeof(char));    

			out_file.write((char *)&node_array[i]->freq,sizeof(char));

		}

	}

	in_file.open(in_file_name,ios::in|ios::binary);

	in_file.read((char*)&temp,sizeof(char));

	while(!in_file.eof())

	{

		for(i = 0;i < node_array[temp]->code.size();i++)

		{

			ch <<= 1;   //将读到的字符左移一位

			bytenum++;

			if(node_array[temp]->code[i] == '1')

				ch = ch | 1;

			if ( bytenum == 8 )                                       //当字节位移满八次以后进行一次压缩

			{

				out_file.write( (char *)&ch, sizeof(char) );

				bytenum = 0;

				ch = 0;

			}

		}

		in_file.read((char*)&temp,sizeof(char));

	}

	//如果压缩的字节不足8位,则用0补足

	if(bytenum > 0 && bytenum < 8)

	{

		ch <<= (8 - bytenum);

		out_file.write((char*)&ch,sizeof(char));

	}

	in_file.close();

	out_file.close();

}



//将压缩好的文件解压回去

void Huffman::decompress_to_file()

{

	int temp,num,i,totalcount;

	unsigned char ch;

	decompress_file.open(out_file_name);

	out_file.open(in_file_name,ios::in|ios::binary);

	out_file.read((char*)&ch,sizeof(char));

	decodingnum = int(ch);     //表头所记录的不同类型的字符数目

	num = decodingnum;

	cout << num << endl;

	cout << out_file_name <<endl;

	out_file.read((char*)&ch,sizeof(char));

	while(num)                ////从新的压缩文件中读取编码情况

	{

		temp = (int)ch;

		node_array[temp]->id = ch;

		out_file.read((char*)&ch,sizeof(char));

		node_array[temp]->freq = int(ch);

		pq.push(node_array[temp]);

		out_file.read((char*)&ch,sizeof(char));

		num--;

	}

	create_huffman_tree();

	totalcount = root->freq;

	while(!out_file.eof())

	{

		for(i = 7;i >= 0;i--)

		{

			temp = (ch >> i)&1;  //每次提出最开头的一位,这样表达的好处是ch并没改变其值

			if(root->left == NULL && root->right == NULL)   //当到达哈夫曼树的叶子时

			{

				decompress_file << root->id;

				root = pq.top();    //返回哈夫曼树顶部

				decodingnum--;

				if(!totalcount)

					return;

			}

			//当为"0",向左子树迭代

			if(temp == 0)

			{

				root = root->left;

			}

			//当为"1",向右子树迭代

			else

			{

				root = root->right;

			}

		}

		out_file.read((char*)&ch,sizeof(char));

	}

	out_file.close();

	decompress_file.close();

}

















 

//test.cpp

#include <iostream>

#include <string>

#include <fstream>

#include "Huffman_H.h"

using namespace std;

/*

int main(int argc,char *argv[])

{

	if(argc != 3)

	{

		cout << "Usage:\n\t huffmancoding inputfile outputfile" << endl;

		exit(1);

	}

	Huffman h(argv[1],argv[2]);

	h.create_pq();

	h.create_huffman_tree();

	h.calculate_huffman_codes(h.root);

	h.save_to_file();

	cout << endl;

	return 0;

}

*/

/*压缩情况

int main()

{

	string s1,s2;

	cin >> s1;

	cin >> s2;

	Huffman h(s1,s2);

	h.create_pq();

	h.create_huffman_tree();

	h.calculate_huffman_codes(h.root);

	h.save_to_file();

	cout << "Done" << endl;

	return 0;

}

*/

//

int main()

{

	string s1,s2;

	cin >> s1;

	cin >> s2;

	Huffman h(s1,s2);

	h.decompress_to_file();

	cout << "Done!" << endl;

	return 0;

}

//

 

你可能感兴趣的:(Huffman)