优先队列构造哈夫曼编码(文件/map)

在这里插入图片描述在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

**

不使用文件进行存储:

**

#include<iostream>
#include<fstream>
#include<queue>
#include<string>
#include<map>
using namespace std;

template<class T>
struct HuffmanNode {
	double val;
	T name;
	HuffmanNode* left,*right;
};
class compare {
public:
	bool operator()(HuffmanNode<char>* h1, HuffmanNode<char>* h2) {
		return h1->val > h2->val;//其中这个不可以写为一个函数(因为优先队列根本不会用这个函数),只能够运算符重载.优先队列默认为大顶堆,且第三个元素必须为类	
	}
};

class HuffmanTree {
public:

	HuffmanNode<char>* init(int n) {
		priority_queue < HuffmanNode<char>*, vector<HuffmanNode<char>*>,compare>q;//后面输入的权值如果和原本有的元素的权值相同,则原本有的排在前面,是稳定排序
		
		while (n--) {
			HuffmanNode<char>* h = new HuffmanNode<char>;
			cin >> h->name >> h->val;//点和箭头要区分,如果是空格,cin会跳过,在调试的时候显示为下一个字符
			h->left = h->right = NULL;
			q.push(h);
		}

		while (q.size()>1)
		{
			HuffmanNode<char>* root = new HuffmanNode<char>;
			root->left = q.top(); q.pop();
			root->right = q.top(); q.pop();
			root->val = root->left->val + root->right->val;
			root->name = '*';//用于印哈夫曼树的时候显示为内部节点
			q.push(root);
			Root = root;
		}
		coding(Root,'0');//除了手工输入如样例点之外,当设置为字符的时候要输入‘0’而不是0
		return Root;
	}

	void coding(HuffmanNode<char>* root,char num) {
		static string s;
		if (num == '0')
			s.push_back('0');//只能push一个字符常量!!所以可以用这种方式
		else
			s.push_back('1');
		
		if (!root->left && !root->right) {
			m[root->name] = s.substr(1,s.length()-1); //如果不用文件存储则用unordered_map
			return;
		}
		coding(root->left,'0');
		s.pop_back();
		coding(root->right,'1');
		s.pop_back();

	}

	void Encoding(char c) {
		cout << m[c];
	}

	int Decoding(HuffmanNode<char>* root, string s, int i) {
		static int sum = -1;
		if (root) {
			if (!root->left && !root->right) {
				sum = i;
				cout << root->name;
				return i;//仅仅返回到上一级 而不是退出函数的返回值 因此在“上一级函数”还要继续返回
			}

			if (s[i] == '0')
				Decoding(root->left, s, i + 1);//如果仅仅是下级函数需要更改后的i而i本身并不需要改变,可以用+1的方式而不是++
			else
				Decoding(root->right, s, i + 1);
		}
		return sum;
	}

	void Print(string EncodingS) {
		int k = 0;
		for (int i = 0; i < EncodingS.size(); ++i) {
			k += m[EncodingS[i]].size();
			if(k<50)
				cout << m[EncodingS[i]];
			else {
				k-= m[EncodingS[i]].size();//当总数到达五十的时候就应该换行输出
				for (int ii = 0; ii < 50 - k; ++ii)
					cout << m[EncodingS[i]][ii];
				cout << endl;
				k = 0;
			}
			
				
		}
		cout << endl;
	}

	void TreePrinting(HuffmanNode<char>* root) {//层次遍历
		if (root) {
			queue < HuffmanNode<char>* > qu;
			qu.push(root);
			while (!qu.empty()) {
				root = qu.front(); qu.pop();
				cout << root->name;
				if(root->left)
					qu.push(root->left);
				if(root->right)
					qu.push(root->right);
			}
			cout << endl;
		}
	}

private:
	HuffmanNode<char>* Root;
	map<char, string>m;
}huff;

int main() {

	int choice;
	HuffmanNode<char>* Root=NULL;
	string EncodingS,DecodingS;
	while (1) {
		cout << "--------请输入您需要的序号----------" << endl;
		cout << "-------------1.初始化---------------" << endl;
		cout << "-------------2.编码-----------------" << endl;
		cout << "-------------3.译码-----------------" << endl;
		cout << "-------------4.印代码文件-----------" << endl;
		cout << "-------------5.印哈夫曼树-----------" << endl;
		cout << "-------------6.退出-----------------" << endl;
		cin >> choice;

		switch (choice)
		{
			case 1:
				int n;
				cin >> n;
				Root=huff.init(n);
				break;
			case 2:
				cin >> EncodingS;
				for (int i = 0; i < EncodingS.size(); ++i) {
					huff.Encoding(EncodingS[i]);
					
				}
				cout << endl;
				break;
			case 3:
				cin >> DecodingS;
				while (!DecodingS.empty()) {
					int i=huff.Decoding(Root, DecodingS, 0);
					DecodingS = DecodingS.substr(i, DecodingS.length() - i);
				}
				cout << endl;
				break;
			case 4:
				huff.Print(EncodingS);
				break;
			case 5:
				huff.TreePrinting(Root);
				break;
			case 6:
				exit(1);
				break;
			default:
				cout << "您输入的序号有误,请重新输入!" << endl;
				break;
		}
	}
}

**

使用文件进行存储

**

#include<iostream>
#include<fstream>
#include<queue>
#include<string>
#include<map>
using namespace std;
ifstream in, in2;
ofstream out;//ASCII码文件不能够同时进行输入输出

template<class T>
struct HuffmanNode {
	double val;
	T name;
	HuffmanNode* left, * right;
};
class compare {
public:
	bool operator()(HuffmanNode<char>* h1, HuffmanNode<char>* h2) {
		//其中这个不可以写为一个函数(因为优先队列根本不会用这个函数),只能够运算符重载.优先队列默认为大顶堆,且第三个元素必须为类	
		return h1->val > h2->val;
	}
};

class HuffmanTree {
public:

	HuffmanNode<char>* init(int n) {
		//后面输入的权值如果和原本有的元素的权值相同,则原本有的排在前面,是稳定排序
		priority_queue < HuffmanNode<char>*, vector<HuffmanNode<char>*>, compare>q;
		
		while (n--) {
			HuffmanNode<char>* h = new HuffmanNode<char>;
			//点和箭头要区分,如果是空格,cin会跳过,在调试的时候显示为下一个字符
			cin >> h->name >> h->val;
			h->left = h->right = NULL;
			q.push(h);
		}
		
		while (q.size() > 1)
		{
			HuffmanNode<char>* root = new HuffmanNode<char>;
			root->left = q.top(); q.pop();
			root->right = q.top(); q.pop();
			root->val = root->left->val + root->right->val;
			root->name = '*';//用于印哈夫曼树的时候显示为内部节点
			q.push(root);
			Root = root;
		}
		//除了手工输入如样例点之外,当设置为字符的时候要输入‘0’而不是0
		coding(Root, '0');
		return Root;
	}

	void coding(HuffmanNode<char>* root, char num) {
		static string s;
		if (num == '0')
			s.push_back('0');//只能push一个字符常量!!所以可以用这种方式
		else
			s.push_back('1');

		if (!root->left && !root->right) {
			// 如果不用文件存储则用unordered_map
			//m[root->name] = s.substr(1,s.length()-1);
			out.open("hfmTree.txt", ios::app);
			string t = s.substr(1, s.length() - 1);
			out << root->name << " " << t << endl;
			out.close();
			return;
		}
		coding(root->left, '0');
		s.pop_back();
		coding(root->right, '1');
		s.pop_back();

	}

	void Encoding(char c) {
		//cout << m[c];
		char t; string s;
		in.open("hfmTree.txt", ios::in);
		out.open("CodeFile.txt", ios::app);
		while (!in.eof()) {
			in >> t >> s;
			if (t == c) {
				out << s;
				out.close();
				in.close();
				break;
			}
		}
		out.close(); in.close();
	}

	int Decoding(HuffmanNode<char>* root, string s, int i) {
		static int sum = -1;
		if (root) {
			if (!root->left && !root->right) {
				out.open("Textfile.txt", ios::app);
				//由于输入的时候以#代替空格,现在在编码的时候把空格转回来
				if (root->name == '#')
					root->name = ' ';
				out << root->name;
				out.close();
				sum = i;
				//仅仅返回到上一级 而不是退出函数的返回值 因此在“上一级函数”还要继续返回
				return i;
			}
			//如果仅仅是下级函数需要更改后的i而i本身并不需要改变,可以用+1的方式而不是++
			if (s[i] == '0')
				Decoding(root->left, s, i + 1);
			else
				Decoding(root->right, s, i + 1);
		}
		return sum;
	}

	void Print() {
		char c;
		in.open("CodeFile.txt", ios::in);//在文件流没有关闭的时候又开一次会导致烫烫烫烫等乱码
		out.open("CodePrin.txt", ios::app);
		while (!in.eof()) {
			for (int i = 0; i < 50; ++i) {
				in >> c;
				if (in.eof())break;
				/*
				* eof遇到的小问题
				eof函数只有在读入不成功后才会置为true
				比如 输入序列abbcad,当第一次读入d后,eof仍为false,再次符合循环条件;
				只有当下一次读入,未读进去数据后,eof置为true,此时临时变量仍为上次的值,所以最后会输出两个d
				所以应该在读取文件之后,再加一个if (in.eof())break;进行判断
				*/
				cout << c;
				out << c;
			}
			cout << endl;
			out << endl;
		}
		in.close();
		out.close();
	}

	void TreePrinting(HuffmanNode<char>* root) {//层次遍历
		
		if (root) {
			queue < HuffmanNode<char>* > qu;
			qu.push(root);
			while (!qu.empty()) {
				root = qu.front(); qu.pop();
				cout << root->name;
				out << root->name;
				if (root->left)
					qu.push(root->left);
				if (root->right)
					qu.push(root->right);
			}
			cout << endl;
			out<< endl;
		}
	}


private:
	HuffmanNode<char>* Root;
	//map<char, string>m;
}huff;

int main() {

	int choice;
	HuffmanNode<char>* Root = NULL;
	string s;
	while (1) {
		cout << "--------请输入您需要的序号----------" << endl;
		cout << "-------------1.初始化---------------" << endl;
		cout << "-------------2.编码-----------------" << endl;
		cout << "-------------3.译码-----------------" << endl;
		cout << "-------------4.印代码文件-----------" << endl;
		cout << "-------------5.印哈夫曼树-----------" << endl;
		cout << "-------------6.退出-----------------" << endl;
		cin >> choice;

		switch (choice)
		{
		case 1:
			//out和app的区别是,一个打开文件就删除里面所有内容,另一个是在文件末尾加内容
			//这二个文件都应该在每次打开程序的时候删除里面所有内容。每次的内容都应该根据输入的编码的变化和要翻译的文件的变化而变化
			out.open("hfmTree.txt", ios::out);
			out.close();
			out.open("CodeFile.txt", ios::out);
			out.close();
			out.open("Textfile.txt", ios::out);
			out.close();
			out.open("CodePrin.txt", ios::out);
			out.close();
			out.open("TreePrint.txt", ios::out);
			out.close();
			int n;
			cin >> n;
			Root = huff.init(n);
			break;
		case 2:
			out.open("CodeFile.txt", ios::out);
			out.close();
			out.open("Textfile.txt", ios::out);
			out.close();
			out.open("CodePrin.txt", ios::out);
			out.close();
			out.open("TreePrint.txt", ios::out);
			out.close();
			in2.open("ToBeTran.txt", ios::in);//一个in不能同时打开两个文件
			getline(in2, s);//直接cin是会跳过空格的
			for (int i = 0; i < s.size(); ++i) {
				if (s[i] == ' ') {
					s[i] = '#';
				}
				huff.Encoding(s[i]);
			}
			out.open("CodeFile.txt", ios::app);
			out << endl;
			out.close();
			in2.close();
			break;
		case 3:
			in.open("CodeFile.txt", ios::in);
			in >> s;
			while (!s.empty()) {
				int i = huff.Decoding(Root, s, 0);
				s = s.substr(i, s.length() - i);
			}
			cout << endl;
			in.close();
			break;
		case 4:
			huff.Print();
			break;
		case 5:
			out.open("TreePrint.txt", ios::in);
			huff.TreePrinting(Root);
			out.close();
			break;
		case 6:
			exit(1);
			break;
		default:
			cout << "您输入的序号有误,请重新输入!" << endl;
			break;
		}
	}
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值