您的位置:首页 > 理论基础 > 数据结构算法

南邮数据结构实验2 (2)哈夫曼编码和编译系统

2014-11-03 09:15 309 查看
哈夫曼编码和编译系统
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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: