《資料結構與演算法設計》實驗報告書之二叉樹的基本操作實現及其應用
《資料結構與演算法設計》實驗報告書之二叉樹的基本操作實現及其應用
實驗專案
二叉樹的基本操作實現及其應用
實驗目的
1.熟悉二叉樹結點的結構和對二叉樹的基本操作。
2.掌握對二叉樹每一種操作的具體實現。
3.學會利用遞迴方法編寫對二叉樹這種遞迴資料結構進行處理的演算法。
4.會用二叉樹解決簡單的實際問題。
實驗內容
設計程式實現二叉樹結點的型別定義和對二叉樹的基本操作。該程式包括二叉樹結構型別以及每一種操作的具體的函式定義和主函式。
1、採用二叉樹連結串列作為儲存結構,
2、遞迴建立一個二叉樹
4、按(A:先序 B:中序 C:後序 )遍歷輸出二叉樹的所有結點
5、輸出二叉樹(凹入式)
以上必做,以下選做
6、求二叉樹中所有結點數
7、求二叉樹的深度
8、求二叉樹葉子結點數
9、建立二叉樹其他方法
10、圖形列印二叉樹
演算法設計分析
(一)資料結構的定義
在電腦科學中,二叉樹是每個結點最多有兩個子樹的樹結構。通常子樹被稱作“左子樹”(left subtree)和“右子樹”(right subtree)。二叉樹常被用於實現二叉查詢樹和二叉堆。
一棵深度為k,且有2k-1個節點的二叉樹,稱為滿二叉樹。這種樹的特點是每一層上的節點數都是最大節點數。而在一棵二叉樹中,除最後一層外,若其餘層都是滿的,並且最後一層或者是滿的,或者是在右邊缺少連續若干節點,則此二叉樹為完全二叉樹。具有n個節點的完全二叉樹的深度為floor(log2n)+1。深度為k的完全二叉樹,至少有2(k-1)個葉子節點,至多有2^k-1個節點。
二叉樹儲存結構定義為:
/*定義二叉樹儲存結構*/
typedef struct node
{
datatype data;
struct node *lchild,*rchild;
}treenode,*treelist;
(二)總體設計
實驗總共包括八個函式:主函式,樹初始化函式,根據先序序列和中序序列建立二叉樹函式,先序建立二叉樹函式,先序遍歷演算法函式,中序遍歷演算法函式,後序遍歷演算法函式,列印二叉樹函式。
主函式:統籌呼叫各個函式以實現相應功能
Int main()
void execute()
樹初始化函式:建立樹的初始化
void treeinit(treelist &bt)
根據先序序列和中序序列建立二叉樹函式:根據先序序列和中序序列建立二叉樹
treelist treecreate4(char *p,char *m,int len)
先序建立二叉樹函式函式:根據先序序列建立二叉樹
treelist treecreate()
先序遍歷二叉樹函式:利用先序遍歷的方法遍歷整棵樹
void DLR( node *root )
中序遍歷二叉樹函式:利用中序遍歷的方法遍歷整棵樹
void LDR(node *root)
後序遍歷二叉樹函式:利用後序遍歷的方法遍歷整棵樹
void LRD (node *root)
列印二叉樹函式:利用遞迴的方法列印整棵樹
void printInorder(node *root,int height,string to,int len)
void printTree(node *root)
(三)各函式的詳細設計:
主函式main()
主要就是進行功能的實現。
樹初始化函式void treeinit(treelist &bt):
建立樹的初始化
根據先序序列和中序序列建立二叉樹函式treelist treecreate4(char *p,char *m,int len):
根據先序序列和中序序列建立二叉樹,判斷根節點的位置以及葉子節點,通過一層一層的遞迴實現建立。
先序建立二叉樹函式函式treelist treecreate():
根據先序序列建立二叉樹,通過輸入一個一個的字元建立二叉樹,也是通過遞迴實現,一‘-’表示該節點為空。
先序遍歷二叉樹函式void DLR( node *root ):
利用先序遍歷的方法遍歷整棵樹,先從跟節點開始,後左右遍歷。
中序遍歷二叉樹函式void LDR(node *root):
利用中序遍歷的方法遍歷整棵樹,先從左孩子開始,再根節點,最後遍歷右孩子。
後序遍歷二叉樹函式void LRD (node *root):
利用後序遍歷的方法遍歷整棵樹,先從左孩子開始,之後從右孩子遍歷,最後再根節點。
列印二叉樹函式void printInorder(node *root,int height,string to,int len) void printTree(node *root):
利用遞迴的方法列印整棵樹
實驗測試結果
先序和中序結果:
先序建立結果:
實驗總結:(100字到200字)
此部分附上主要程式程式碼和相關的註釋說明、除錯資料及過程、問題及解決辦法。 (最重要)
(1)除錯過程中主要遇到哪些問題?是如何解決的?
答:在建立二叉樹的時候還是遇見過一些問題的,就拿先序和中序建立來說,找位置有一些難度,看了老師的程式碼才發現並沒有自己想的那麼複雜。還有列印二叉樹,說實話,還是不怎麼會,這個程式碼是網上參考的,後面要多加思考,爭取能夠自己寫出列印二叉樹的函式。
(2)經驗和體會
答:還是那句老話,多敲程式碼自己練習,有時間把多複習多上網查查資料,增加自己對二叉樹資料結構的理解。
附錄 實驗程式程式碼(該部分請加註釋)
/tree.h函式程式碼/
typedef struct node
{
datatype data;
struct node *lchild,*rchild;
}treenode,*treelist;
//樹初始化
void treeinit(treelist &bt)
{
bt=NULL;
}
treelist treecreate4(char *p,char *m,int len) //根據先序序列和中序序列建立二叉樹;
{
//*P存放先序序列,*m存放中序序列,len為m中字元個數;
treelist s;
char *q;
int k;
if(len<=0)
return NULL;
s=new treenode(); //建立二叉樹結點s;
s->data=*p;
figure++;
for(q=m;q<m+len;q++) //在中序序列中找等於*p的位置k;
{
if(*q==*p)
break;
}
k=q-m;
s->lchild=treecreate4(p+1,m,k); //遞迴構造左子樹;
s->rchild=treecreate4(p+k+1,q+1,len-k-1); //遞迴構造右子樹;
return s;
}
treelist treecreate() //先序建立二叉樹
{
treelist s;
char c;
std::cin>>c;
if(c == '-'){
s = NULL;
}else{
s = new treenode();
s->data = c;
figure++; //構造根結點
s->lchild = treecreate(); //構造左子樹
s->rchild = treecreate(); //構造右子樹
}
return s;
}
//先序遍歷演算法
void DLR( node *root )
{
if (root !=NULL) //非空二叉樹
{
cout<<root->data; //訪問D
DLR(root->lchild); //遞迴遍歷左子樹
DLR(root->rchild); //遞迴遍歷右子樹
}
}
//中序遍歷演算法
void LDR(node *root)
{
if(root !=NULL)
{
LDR(root->lchild);
cout<<root->data;
LDR(root->rchild);
}
}
//後序遍歷演算法
void LRD (node *root)
{
if(root !=NULL)
{
LRD(root->lchild);
LRD(root->rchild);
cout<<root->data;
}
}
void printInorder(node *root,int height,string to,int len)
{
if(NULL == root)
return ;
printInorder(root->rchild,height+1,"_",len);//先列印右子樹
//列印跟節點
stringstream ss;
ss << root->data;
string val = to + ss.str() + to;
int lenM = val.length();
int lenL = (len-lenM)/2;
int lenR = len -lenM-lenL;
val = string(lenL,' ') + val + string(lenR,' ');
std::cout<<string(height*len,' ')<<val<<std::endl;
printInorder(root->lchild,height+1,"_",len);
return ;
}
void printTree(node *root)
{
cout << "Binary Tree:" << endl;
printInorder(root,0,"_",5);
cout << endl;
}
/menu.h選單函式程式碼/
#ifndef MENU_H_INCLUDED
#define MENU_H_INCLUDED
void menu(){
std::cout<<"\n";
std::cout<<" **********************二叉樹的應用**********************\n";
std::cout<<" * *\n";
std::cout<<" * a:(先中)建立二叉樹 b:先序建立二叉樹 *\n";
std::cout<<" * c:先序遍歷 d:中序遍歷 *\n";
std::cout<<" * e:後序遍歷 f:二叉樹的節點數 *\n";
std::cout<<" * g:列印二叉樹(凹入型) h:退出程式 *\n";
std::cout<<" * *\n";
std::cout<<" ********************************************************\n";
}
#endif // MENU_H_INCLUDED
/主函式程式碼/
#include <iostream>
#include <string>
#include <cstring>
#include <sstream>
using namespace std;
#define maxsize 100
#define infinity 10000 /*定義一個無限大的值*/
typedef char datatype;
int figure=0;//所含結點個數
#include "menu.h"
#include "tree.h"
typedef treelist elem;
char str1[100],str2[100];
int i,j,length;//lever表示層次,h高度
treelist bt;
int main()
{
treeinit(bt);
void execute();
execute();
return 0;
}
void execute()
{
char a;
for(;;)
{
menu();
cin>>a;
switch (a)
{
case 'a':
cout<<"請輸入先序序列和中序序列:"<<endl;
cin>>str1>>str2;
length=strlen(str1);
bt=treecreate4(str1,str2,length);
break;
case 'b':
cout<<"請輸入先序序列:"<<endl;
bt=treecreate();
break;
case 'c':
cout<<"先序序列為:"<<endl;
DLR(bt);
break;
case 'd':
cout<<"中序序列為:"<<endl;
LDR(bt);
break;
case 'e':
cout<<"後序序列為:"<<endl;
LRD(bt);
break;
case 'f':
cout<<"二叉樹的節點數為:"<<endl;
cout<<figure<<endl;
break;
case 'g':
cout<<"列印樹(凹入式):"<<endl;
printTree(bt);
break;
case 'h':
cout<<" 再見!"<<endl;
return ;
default:
cout<<"輸入的字元有誤,請重新輸入!!"<<endl;
break;
}
}
}