算法:Haffman,DFS
数据结构:queue,Haffman Tree
PS:使用链表建树,但用数组存树操作更方便
// Huffman.cpp : 定义控制台应用程序的入口点。
//
//#include "stdafx.h"
#include "iostream"
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "string"
#include "queue"
#include "fstream"
const int max_nodenum=100; //最多字符数
using namespace std;
struct Node
{
char ch;
double weight;
Node* parent;
Node* Lchild;
Node* Rchild;
Node()
{
ch = NULL;
weight = 0;
parent = NULL;
Lchild = NULL;
Rchild = NULL;
}
bool operator < (const Node &a)const
{
return a.weight < weight;
}
}Hf[max_nodenum]; //Hf[n]用来存储符号信息,和建树无关
struct Info //打表保存字符编码信息
{
char ch;
string code;
}info[max_nodenum];
Node *root; //huffman树根
void CreateTree()
{
root = new Node;
priority_queue <Node> Queue;
ifstream fin("hfmTree.txt"); //在文件中读取已保存的数据
int n;
fin >> n;
for (int i = 0; i < n; i++)
{
fin >> Hf[i].ch >> Hf[i].weight;
Queue.push(Hf[i]);
}
while (Queue.size() > 1) //建树 从下向上
{
Node* a = new Node; //左子树
if (Queue.top().ch == NULL)
{
*a = Queue.top();
a->Lchild->parent = a; //***被坑了好久
a->Rchild->parent = a; //***
}
a->ch = Queue.top().ch;
a->weight = Queue.top().weight;
Queue.pop();
Node *b = new Node; //右子树
if (Queue.top().ch == NULL)
{
*b = Queue.top();
b->Lchild->parent = b; //***
b->Rchild->parent = b; //***
}
b->ch = Queue.top().ch;
b->weight = Queue.top().weight;
Queue.pop();
Node *ab = new Node; //父节点
ab->weight = a->weight + b->weight;
ab->Lchild = a;
ab->Rchild = b;
a->parent = ab;
b->parent = ab;
Queue.push(*ab);
if (Queue.size() == 1)
root = ab; //树根
}
}
void Initial()
{
int choose;
cout << "建树:1.在控制台输入 2.在'hfmTree.txt'文件中读取" << endl;
cin >> choose;
if (choose == 1)
{
ofstream fclear("hfmTree.txt", std::ofstream::out | std::ofstream::trunc); //清空原有文件
cout << "控制台建树:输入字符集大小 n" << endl;
ofstream fout("hfmTree.txt"); //在文件中输出
int n;
cin >> n;
fout << n << endl;
cout << "输入:字符 权值" << endl;
for (int i = 0; i < n; i++) //输入并输出到文件
{
cin >> Hf[i].ch >> Hf[i].weight;
fout << Hf[i].ch << " " << Hf[i].weight << endl;
}
CreateTree(); //文件中读取数据建树
cout << "建树成功,并保存到 'hfmTree.txt'中" << endl;
}
else if (choose == 2)
{
CreateTree(); //文件中读取数据建树
//cout << root->weight << " " << root->Lchild->parent->weight;
cout << "文件中读取数据建树成功" << endl;
}
/* 4 a 5 s 10 d 15 f 10 */
}
/*void tv(Node* rot) { cout << rot->weight << " " << rot->ch << endl; if (rot->Lchild == NULL && rot->Rchild == NULL) return; //if(rot->ch!=NULL) if(rot->Lchild!=NULL) tv(rot->Lchild); if(rot->Rchild!=NULL) tv(rot->Rchild); }*/
int info_num = 0; //字符编码信息数量
void Traverse(Node *rot)
{
if (rot->Lchild == NULL && rot->Rchild == NULL)
{
info[info_num].ch = rot->ch;
Node* cur=rot;
//cout << cur->weight << " " << cur->parent->parent->weight;
while (cur->parent!=NULL)
{
//cout << cur->weight << " "<<cur->parent->weight;
if (cur->parent->Lchild == cur)
{
info[info_num].code += '0';
}
if (cur->parent->Rchild == cur)
{
info[info_num].code += '1';
}
cur=cur->parent;
}
//cout << info[info_num].ch << " " << info[info_num].code << endl;
int codelen = info[info_num].code.length();
for (int i = 0; i < codelen/2; i++) //逆置得正序编码
{
int temp = info[info_num].code[i];
info[info_num].code[i] = info[info_num].code[codelen - i - 1];
info[info_num].code[codelen - i - 1] = temp;
}
info_num++;
return;
}
if (rot->Lchild != NULL)
Traverse(rot->Lchild);
if(rot->Rchild!=NULL)
Traverse(rot->Rchild);
}
void Encoding()
{
info_num = 0;
memset(info, 0, sizeof(info)); //初始化
Traverse(root); //遍历打表记录编码映射
cout << "编码映射如下:" << endl;
for (int i = 0; i < info_num; i++)
{
cout << info[i].ch << " " << info[i].code << endl;
}
//tv(root);
cout << "编码:1.控制台输入数据 2.从文件'ToBeTran.txt'中读取" << endl;
int choose;
cin >> choose;
ofstream fout("CodeFile.txt"); //编码结果保存文件
if (choose == 1)
{
cout << "输入字符序列:" << endl;
string str;
cin >> str;
//Traverse(root);
//cout << 111000;
/* for (int i = 0; i < info_num; i++) { cout << info[i].ch<<" "; cout << info[i].code<<endl; } */
for (int i = 0; i < str.length(); i++)
{
for (int j = 0; j < info_num; j++)
{
if (str[i] == info[j].ch)
{
cout << info[j].code;
fout << info[j].code;
}
}
}
cout << endl;
cout << "以上编码结果已保存到文件'CodeFile.txt'中" << endl;
}
else if (choose == 2)
{
ifstream fin("ToBeTran.txt");
string str;
fin >> str;
//Traverse(root);
for (int i = 0; i < str.length(); i++)
{
for (int j = 0; j < info_num; j++)
{
if (str[i] == info[j].ch)
{
cout << info[j].code;
fout << info[j].code;
}
}
}
cout << endl;
cout << "以上编码结果已保存到文件'CodeFile.txt'中" << endl;
}
}
void Decoding()
{
string str;
ifstream fin("CodeFile.txt");
fin >> str;
ofstream fout("TextFile.txt");
Node* cur = root;
int i=0;
while (i <= str.length())
{
if (cur->Lchild == NULL && cur->Rchild == NULL)
{
cout << cur->ch;
fout << cur->ch;
cur = root;
}
if (str[i] == '0')
cur = cur->Lchild;
if (str[i] == '1')
cur = cur->Rchild;
i++;
}
cout << endl;
cout<< "以上译码结果已保存到文件'TextFile.txt'中" << endl;
}
int main()
{
cout << "操作菜单:1.建Huffman树 2.编码 3.译码 0.结束"<<endl;
int n;
while (cin >> n && n)
{
switch (n)
{
case 1:Initial();break;
case 2:Encoding(); break;
case 3:Decoding();break;
default:break;
}
cout << "操作菜单:1.建Huffman树 2.编码 3.译码 0.结束" << endl;
}
return 0;
}