哈夫曼编码和编译系统
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; }