优先队列构造哈夫曼编码(文件/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 >> 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) {
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) {
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;//仅仅返回到上一级 而不是退出函数的返回值 因此在“上一级函数”还要继续返回
}
if (s[i] == '0')
Decoding(root->left, s, i + 1);//如果仅仅是下级函数需要更改后的i而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;
if(root->left)
qu.push(root->left);
if(root->right)
qu.push(root->right);
}
cout << endl;
}
}
private:
HuffmanNode<char>* Root;
}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.open("hfmTree.txt", ios::out);//out和app的区别是,一个打开文件就删除里面所有内容,另一个是在文件末尾加内容
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:
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:
huff.TreePrinting(Root);
break;
case 6:
exit(1);
break;
default:
cout << "您输入的序号有误,请重新输入!" << endl;
break;
}
}
}
标签:map,right,哈夫曼,队列,int,HuffmanNode,left,root,out 来源: https://blog.csdn.net/caicai____/article/details/121607614