南郵數據結構、算法實踐周基礎題3(哈夫曼樹及其編碼)

是在一位學長的代碼上改的,學長勿怪~.~

#include <iostream>
#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 Create_code();
	void Create_code_out();
	BTNode<T>*root;
private:
	int i;

	void Create_code(BTNode<T>*t);
	void Create_code_out(BTNode<T>*t);

//	void Make(BTNode<T>*t,char a);

};

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>
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<<"*****************      E--生成編碼  ************************"<<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 << "請輸入相應字符集 :";
	for(i=0;i<num;i++){
        cin >> str[i];
	}
	Ht = CreateHfmTree(weight, str, num);
}


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);
	}
}

int main()     
{
	char choose;
	menu();
	cin >> choose; 	  
	while(choose != 'X')    
	{
		switch(choose)
		{
		    case 'B':
			    Make_Ht();
				Ht.Create_code();
				break;
			case 'E':
				cout << "編碼爲 :" << endl;
				Ht.Create_code_out();
				break;
			case 'X':
				break;
			default:
				cout << " 輸入有誤,請重新輸入!"<<endl;
				break;
		}
		system("PAUSE");
		system("CLS");
		menu(); 
		cin >> choose;
	}
	return 0;
}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章