資料結構|二叉樹的鏈式儲存(實驗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、總體收穫和不足,疑問等。
整體的實驗過程中,我一度因為實驗過程困難而選擇放棄繼續實驗。經過冷靜地思考以及向同學詢問、上網查詢解決方法、查詢課本等方式,最終還是完成了實驗。雖然相關程式碼仍存有瑕疵,但我會繼續努力,繼續更改。
這次實驗,我發現了自己對於理論學習還是存有不足之處,但總得來說,我對理論知識有了更充分的理解,也能較大程度明白執行原理。