1. 程式人生 > >資料結構|二叉樹的鏈式儲存(實驗6.2)

資料結構|二叉樹的鏈式儲存(實驗6.2)

一、實驗目的

1、   熟練理解樹和二叉樹的相關概念,掌握的儲存結構和相關操作實現;

2、   掌握樹的順序結構的實現;

3、   學會運用樹的知識解決實際問題

二、 實驗內容

1、自己確定一個二叉樹(樹結點型別、數目和結構自定)利用鏈式儲存結構方法儲存。實現樹的構造,並完成:

1)用前序遍歷、中序遍歷、後序遍歷輸出結點資料;

2)以合理的格式,輸出各個結點和雙親、孩子結點資訊;

3)輸出所有的葉子結點資訊;

三、實驗步驟

1、依據實驗內容,先確定具體的二叉樹,並說明結點的資料型別;

template <typename T>
class Bitree
{
	public:
		Bitree() { root=Creat(root); }  //建構函式
		~Bitree() { Release(root); }  //解構函式
		void Preorder() { Preorder(root); }  //前序遍歷
		void Inorder() { Inorder(root); }   //中序遍歷
		void Postorder() { Postorder(root); }   //後序遍歷
		void Leverorder();    //層序遍歷
		void findmessage(T x){ findmessage(root,x); }  //查詢各結點的資訊
	private:
		BiNode<T> *root;  //指向根結點的頭指標
		BiNode<T> *Creat(BiNode<T> *bt);   //建構函式呼叫
		void Release (BiNode<T> *bt);
		void Preorder (BiNode<T> *bt);
		void Inorder (BiNode<T> *bt);
		void Postorder (BiNode<T> *bt);
		void findmessage(BiNode<T> *bt,T x);
		void Parent(BiNode<T> *bt,T x);
};


2、設計具體的演算法;

  2.1建構函式:建立一個二叉樹;

  2.2建立二叉連結串列演算法:

      ①輸入資料資訊,空樹的符號為“#”

      ②生成結點,分別遞迴建立左子樹和右子樹。

  2.3解構函式:採用後序遍歷,先後釋放左子樹、右子樹、根結點。

  2.4前序遍歷函式:遞迴呼叫,先後遍歷根結點的資料域、左子樹、右子樹。

  2.5中序遍歷函式:遞迴呼叫,先後遍歷根結點的左子樹、資料域、右子樹。

  2.6後序遍歷函式:遞迴呼叫,先後遍歷根結點的左子樹、右子樹資料域

3、寫出完整程式;

由於結點元素型別不確定,因此採用C++模板機制。

原始碼如下:

#include<iostream>
using namespace std;

template <typename T>
struct BiNode
{
	T data;
	BiNode<T> *lchild,*rchild;
};

template <typename T>
class Bitree
{
	public:
		Bitree() { root=Creat(root); }  //建構函式
		~Bitree() { Release(root); }  //解構函式
		void Preorder() { Preorder(root); }  //前序遍歷
		void Inorder() { Inorder(root); }   //中序遍歷
		void Postorder() { Postorder(root); }   //後序遍歷
		void Leverorder();    //層序遍歷
		void findmessage(T x){ findmessage(root,x); }  //查詢各結點的資訊
	private:
		BiNode<T> *root;  //指向根結點的頭指標
		BiNode<T> *Creat(BiNode<T> *bt);   //建構函式呼叫
		void Release (BiNode<T> *bt);
		void Preorder (BiNode<T> *bt);
		void Inorder (BiNode<T> *bt);
		void Postorder (BiNode<T> *bt);
		void findmessage(BiNode<T> *bt,T x);
		void Parent(BiNode<T> *bt,T x);
};

template <typename T>
void Bitree<T>::Preorder(BiNode<T> *bt)
{
	if(bt==NULL) return;    //遞迴呼叫的結束條件
	else {
		cout<<bt->data<<" ";    //訪問根結點的資料域
		Preorder(bt->lchild);  //前序遞迴遍歷左子樹
		Preorder(bt->rchild);  //前序遞迴遍歷右子樹
	}
}

template <typename T>
void Bitree<T>::Inorder(BiNode<T> *bt)
{
	if(bt==NULL) return;    //遞迴呼叫的結束條件
	else {
		Inorder(bt->lchild);  //中序遞迴遍歷左子樹
		cout<<bt->data<<" ";    //訪問根結點的資料域
		Inorder(bt->rchild);  //中序遞迴遍歷右子樹
	}
}

template <typename T>
void Bitree<T>::Postorder(BiNode<T> *bt)
{
	if(bt==NULL) return;    //遞迴呼叫的結束條件
	else {
		Postorder(bt->lchild);  //後序遞迴遍歷左子樹
		Postorder(bt->rchild);  //後序遞迴遍歷右子樹
		cout<<bt->data<<" ";    //訪問根結點的資料域
	}
}

template <typename T>
void Bitree<T>::Leverorder()
{
	front = rear =-1;  //
	if(root == NULL) return;  //
	Q[++rear] = root;
	while(front!=rear)
	{
		q=Q[++front];   //
		cout<<q->data;
		if(q->lchild !=NULL) Q[++rear]=q->lchild;
		if(q->rchild !=NULL) Q[++rear]=q->rchild;
	}
}

template <typename T>
BiNode<T> *Bitree<T>::Creat(BiNode<T> *bt)
{
	char ch;
	cout<<"輸入二叉樹的各個結點資料,空樹為# :"<<endl;
	cin>>ch;
	if(ch == '#') bt=NULL;
	else {
		bt= new BiNode<T>; bt->data = ch;
		bt->lchild=Creat(bt->lchild);
		bt->rchild=Creat(bt->rchild);
		
	}
	return bt;
}

template <typename T>
void Bitree<T>::Release(BiNode<T> *bt)
{
	if(bt!=NULL) {
		Release(bt->lchild);
		Release(bt->rchild);
		delete bt;
	}
}

template <typename T>
void Bitree<T>::findmessage(BiNode<T> *bt,T x)
{
	int data;
	if(bt==NULL) return;
	else{
		if(bt->data == x){
			cout<<"結點"<<bt->data<<endl;
            if(bt->lchild!=NULL) cout<<"左孩子為:"<<bt->lchild->data<<endl;  
			else cout<<"無左孩子"<<endl;  
            if(bt->rchild!=NULL) cout<<"右孩子為:"<<bt->rchild->data<<endl;
			else cout<<"無右孩子。"<<endl;  
            if(bt==root)  cout<<"該結點為根,無雙親"<<endl;  
            else   Parent(root,x);
		}
        else{  
            findmessage(bt->lchild,x);  
            findmessage(bt->rchild,x);  
        }
    }
}

template<typename T>  
void Bitree<T>::Parent(BiNode<T> *bt,T x)  
{  
    if(bt==NULL) return;  
    else  
    {  
        if(bt->lchild->data==x||bt->rchild->data==x)    cout<<"雙親為:"<<bt->data<<endl;  
        else{  
            Parent(bt->lchild,x);  
            Parent(bt->rchild,x);  
        }  
    }  
}

void main()
{
	char x; int select;
	cout<<"建立物件"<<endl;
	Bitree<char>a;
	cout<<"【現以各種便利方式輸出結點資料】"<<endl;
	cout<<"前序遍歷:"<<endl;
	a.Preorder();
	cout<<endl;
	cout<<"中序遍歷:"<<endl;
	a.Inorder();
	cout<<endl;
	cout<<"後序遍歷:"<<endl;
	a.Postorder();
	cout<<endl;
	cout<<"【輸出結點資訊】"<<endl;
	for(int i=0;i=1;i=select){
		cout<<"請輸入需要查詢資訊的結點元素"<<endl;
	    cin>>x;
        a.findmessage(x);
     	cout<<"是否需要繼續查詢?"<<endl<<"是:1      否:0"<<endl;
	    cin>>select;
		if (select==0) break;
	}
}

4、總結、執行結果和分析演算法效率。

 ①總結

  在程式內建立物件,並通過呼叫成員函式實現各種功能,如前序遍歷、中序遍歷、後序遍歷,輸出結點資訊等。

 ②執行結果如下:


5、總體收穫和不足,疑問等。

   整體的實驗過程中,我一度因為實驗過程困難而選擇放棄繼續實驗。經過冷靜地思考以及向同學詢問、上網查詢解決方法、查詢課本等方式,最終還是完成了實驗。雖然相關程式碼仍存有瑕疵,但我會繼續努力,繼續更改。

這次實驗,我發現了自己對於理論學習還是存有不足之處,但總得來說,我對理論知識有了更充分的理解,也能較大程度明白執行原理。