哈夫曼编码和编译系统
1.所设计的系统重复显示以下菜单项。
B——建树:读入字符集和各字符频度,建立哈夫曼树。
T——遍历:先序和中序遍历二叉树。
E——生成编码:根据已建成的哈夫曼树,产生各个字符的哈夫曼编码。
C——编码:输入由字符集中字符组成的任意字符串,利用已生成的哈夫曼编码进行编码,显示编码结果,并将输入的字符串及其编码结果分别保存在磁盘文件textfile.txt和codefile.txt中。
D——译码:读入codefile.txt,利用已建成的哈夫曼树进行译码,并将译码结果存入磁盘文件result.txt。
P——打印:屏幕显示文件textfile.txt,codefile.txt,result.txt。
X——退出。
该程序在VC++6.0上编译运行无误
#include <iostream>
#include <fstream>
#include <string>
#include <cstring>
using namespace std;
template<class T>
class PrioQueue //优先权队列类
{
public:
PrioQueue(int mSize = 20);
~PrioQueue(){ delete []q; }
bool IsEmpty() const{ return n == 0; }
bool IsFull() const{ return n == maxSize; }
void Append(const T&x);
void Serve(T&x);
private:
void AdjustDown(int r, int j);
void AdjustUp(int j);
T *q;
int n, maxSize;
};
template<class T>
PrioQueue<T>::PrioQueue(int mSize)
{
maxSize = mSize;
n = 0;
q = new T[maxSize];
}
template<class T>
void PrioQueue<T>::AdjustUp(int j)
{
int i = j;
T temp = q[i];
while (i > 0 && temp < q[(i - 1) / 2])
{
q[i] = q[(i - 1) / 2];
i = (i - 1) / 2;
}
q[i] = temp;
}
template<class T>
void PrioQueue<T>::Append(const T&x) //插入新元素
{
if(IsFull())
{
cout << "Overflow" << endl;
return;
}
q[n++] = x;
AdjustUp(n-1);
}
template<class T>
void PrioQueue<T>::Serve(T&x) //删除堆顶元素
{
if(IsEmpty())
{
cout << "Underflow" << endl;
return;
}
x = q[0];
q[0] = q[--n];
AdjustDown(0, n-1);
}
template<class T>
void PrioQueue<T>::AdjustDown(int r,int j) //向上调整
{
int child = 2 * r + 1;
T temp = q[r];
while(child <= j)
{
if((child < j) && (q[child] > q[child+1]))
child++;
if(temp <= q[child])
break;
q[(child - 1) / 2] = q[child];
child = 2 * child + 1;
}
q[(child - 1) / 2] = temp;
}
template<class T>
struct BTNode //结点类
{
BTNode(){lChild = rChild = NULL;}
BTNode(const T&x, const char &y)
{
element = x;
ch = y;
lChild = rChild = parent = NULL;
memset(z, -1, sizeof(z));
}
BTNode(const T&x, const char &y, BTNode<T>*l, BTNode<T>*r)
{
element = x;
ch = y;
lChild = l;
rChild = r;
parent = NULL;
memset(z, -1, sizeof(z));
}
T element;
BTNode<T> *lChild, *rChild, *parent;
char ch;
int val;
int z[100];
};
template<class T> //二叉树类
class BinaryTree
{
public:
BinaryTree(){root = NULL; i = -1;}
~BinaryTree(){}
void MakeTree(const T&x, const char &y, BinaryTree<T>&left, BinaryTree<T>& right);
void PreOrder(void (*Visit)(T&x));
void InOrder(void (*Visit)(T&x));
void Create_code();
void Create_code_out();
void Code();
void Compile();
void Print();
BTNode<T>*root;
private:
int i;
void PreOrder(void (*Visit)(T&x), BTNode<T>*t);
void InOrder(void (*Visit)(T&x), BTNode<T>*t);
void Create_code(BTNode<T>*t);
void Create_code_out(BTNode<T>*t);
void Code(BTNode<T>*t);
void Make(BTNode<T>*t,char a);
void Compile(BTNode<T>*t);
};
template<class T>
void BinaryTree<T>::MakeTree(const T&x, const char &y, BinaryTree<T>&left, BinaryTree<T>& right) //建树
{
if(root || &left == &right)
return;
root = new BTNode<T>(x, y, left.root, right.root);
if(left.root != right.root)
{
left.root -> parent = root;
right.root -> parent = root;
left.root -> val = 0;
right.root -> val = 1;
}
left.root = right.root = NULL;
}
template<class T> //Visit函数
void Visit(T&x)
{
cout << x << " ";
}
template<class T>
void BinaryTree<T>::PreOrder(void (*Visit)(T&x)) //先序遍历
{
cout << "先序遍历为: ";
PreOrder(Visit, root);
cout << endl;
}
template<class T>
void BinaryTree<T>::PreOrder(void (*Visit)(T&x), BTNode<T>*t)
{
if(t)
{
Visit(t -> element);
PreOrder(Visit, t -> lChild);
PreOrder(Visit, t -> rChild);
}
}
template<class T>
void BinaryTree<T>::InOrder(void (*Visit)(T&x)) //中序遍历
{
cout << "中序遍历为: ";
InOrder(Visit, root);
cout << endl;
}
template<class T>
void BinaryTree<T>::InOrder(void (*Visit)(T&x), BTNode<T>*t)
{
if(t)
{
InOrder(Visit, t -> lChild);
Visit(t -> element);
InOrder(Visit, t -> rChild);
}
}
template<class T>
class HfmTree : public BinaryTree<T> //哈夫曼树类
{
public:
operator T() const{ return weight; }
T getW(){ return weight; }
void putW(const T&x){ weight = x; }
void SetNull(){ root = NULL; }
private:
T weight;
};
template<class T>
HfmTree<T> CreateHfmTree(T w[],char q[],int n) //构造哈夫曼树
{
PrioQueue<HfmTree<T> > pq(n);
HfmTree<T> x, y, z, zero;
for(int i = 0; i < n; i++)
{
z.MakeTree(w[i], q[i], x ,y);
z.putW(w[i]);
pq.Append(z);
z.SetNull();
}
for(i = 1; i < n; i++)
{
pq.Serve(x);
pq.Serve(y);
z.MakeTree(x.getW() + y.getW(), 'e', x, y);
z.putW(x.getW() + y.getW());
pq.Append(z);
z.SetNull();
}
pq.Serve(z);
return z;
}
void menu()
{
cout<<"--------------欢迎使用哈夫曼编码和译码系统------------------"<<endl;
cout<<"************** 请选择下列序号进行运算: *****************"<<endl;
cout<<"***************** B--建树 ************************"<<endl;
cout<<"***************** T--遍历 ************************"<<endl;
cout<<"***************** E--生成编码 ************************"<<endl;
cout<<"***************** C--编码 ************************"<<endl;
cout<<"***************** D--译码 ************************"<<endl;
cout<<"***************** P--打印 ************************"<<endl;
cout<<"***************** X--退出 ************************"<<endl<<endl;
cout<<"--------------------- 输入操作项----------------------------"<<endl;
}
HfmTree<int> Ht;
int num;
void Make_Ht()
{
char str[100];
int weight[100];
cout << "请输入字符个数 :";
cin >> num; //建树
cout << "请输入权值 :";
for(int i = 0; i < num; i++)
cin >> weight[i];
cout << "请输入相应字符集 :";
cin >> str;
Ht = CreateHfmTree(weight, str, num);
}
void Traversal_Ht()
{
Ht.PreOrder(Visit);
Ht.InOrder(Visit);
}
template<class T>
void BinaryTree<T>::Create_code()
{
Create_code(root);
}
template<class T>
void BinaryTree<T>::Create_code(BTNode<T>*t)
{
if(t)
{
if(t -> parent)
{
for(int j = 0; j <= i; j++)
t -> z[j] = t -> parent -> z[j]; //复制双亲的编码域
i++;
t -> z[i] = t-> val; //在编码域中加入自己的编码
}
Create_code(t -> lChild); //递归,先左孩子,再右孩子
Create_code(t -> rChild);
i--;
}
}
template<class T>
void BinaryTree<T>::Create_code_out() //生成编码并输出
{
Create_code_out(root);
}
template<class T>
void BinaryTree<T>::Create_code_out(BTNode<T>*t)
{
if(t)
{
if(t -> lChild == t -> rChild) //叶子结点
{
cout << t -> ch << ":"; //输出叶子结点中的字符
int i = 0;
while(t -> z[i] != -1)
{
cout << t -> z[i]; //输出编码域
i++;
}
cout << endl;
}
Create_code_out(t->lChild);
Create_code_out(t->rChild);
}
}
template<class T>
void BinaryTree<T>::Code()
{
Code(root);
}
template<class T>
void BinaryTree<T>::Code(BTNode<T>*t) //编码
{
ofstream outf("textfile.txt");
if(!outf)
{
cout << "Cannot open the file\n";
return;
}
ofstream outs("codefile.txt",ios::trunc);
if(!outs)
{
cout << "Cannot open the file\n";
return;
}
outs.close();
char str2[100];
cout << "请输入由字符集中字符组成的任意字符串: ";
cin >> str2;
outf << str2;
outf.close();
int l = strlen(str2);
cout << "编码为 :" << endl;
for(int i = 0; i < l; i++)
Make(root, str2[i]);
cout << endl;
}
template<class T>
void BinaryTree<T>::Make(BTNode<T> *t,char a)
{
int i = 0;
if(t)
{
if(t -> ch == a) //找到相应字符
{
ofstream outs("codefile.txt",ios::app);
while(t -> z[i] != -1)
{
cout << t -> z[i]; //输出编码域
outs << t -> z[i]; //将编码写入文件
i++;
}
outs.close();
return;
}
Make(t -> lChild, a);
Make(t -> rChild, a);
}
}
template<class T>
void BinaryTree<T>::Compile() //译码
{
Compile(root);
}
template<class T>
void BinaryTree<T>::Compile(BTNode<T> *t)
{
ifstream inf("codefile.txt");
if(!inf)
{
cout << "Cannot open the file\n";
return;
}
ofstream outs("result.txt",ios::trunc);
if(!outs)
{
cout << "Cannot open the file\n";
return;
}
outs.close();
char *re;
char tmp;
int n = 0;
while(inf.get(tmp) != '\0')
{
n++; //确定字符数量
}
inf.close();
re = new char[n+1];
int n2 = 0;
ifstream in("codefile.txt");
if(!in)
{
cout<<"Cannot open the file\n";
return;
}
while(in.get(tmp) != '\0')
{
re[n2] = tmp; //将字符读入一位数组
n2++;
}
BTNode<T> *c;
cout << "译码为 :";
int n3 = 0;
while(n3 < n)
{
while(t)
{
c = t;
if(re[n3] == '0') //左0右1根据0或1向左走向右走直到叶子结点
t = t -> lChild;
else
t = t -> rChild;
n3++;
}
ofstream outs("result.txt",ios::app);
if(!outs)
{
cout << "Cannot open the file\n";
return;
}
cout << c -> ch; //输出字符
outs << c -> ch; //将结果写进文件
outs.close();
t = root;
n3--;
}
cout << endl;
}
void Print()
{
char str;
ifstream a("textfile.txt");
ifstream b("codefile.txt");
ifstream c("result.txt");
if(!a)
{
cout << "Cannot open the file\n";
return;
}
if(!b)
{
cout << "Cannot open the file\n";
return;
}
if(!c)
{
cout << "Cannot open the file\n";
return;
}
cout << "textfile.txt内的内容为 :";
while(a.get(str) != '\0')
cout << str;
cout << endl;
cout << "codefile.txt内的内容为 :";
while(b.get(str) != '\0')
cout << str;
cout << endl;
cout << "result.txt内的内容为 :";
while(c.get(str) != '\0')
cout << str;
cout << endl;
a.close();
b.close();
c.close();
}
int main()
{
char choose;
menu();
cin >> choose;
while(choose != 'X')
{
switch(choose)
{
case 'B':
Make_Ht();
Ht.Create_code();
break;
case 'T':
Traversal_Ht();
break;
case 'E':
cout << "编码为 :" << endl;
Ht.Create_code_out();
break;
case 'C':
Ht.Code();
break;
case 'D':
Ht.Compile();
break;
case 'P':
Print();
break;
case 'X':
break;
default:
cout << " 输入有误,请重新输入!"<<endl;
break;
}
system("PAUSE");
system("CLS");
menu();
cin >> choose;
}
return 0;
}