數據結構實驗課之二叉樹實驗(一)
該博客待完善,編者目前爲大二學生水平較差,內容僅供參考
實驗內容:
以括號表示法作爲輸入字符串構造一棵二叉樹,完成下列實驗要求:
(1)如果輸入字符串不符合規範,顯示錯誤信息:“輸入錯誤”。
(2)分別顯示該二叉樹的先序、中序和後序遍歷。
(3)求出該二叉樹的高度。
(4)輸出該二叉樹所有的葉子結點。
(5)找出二叉樹中的最大、最小值結點,並寫出他們的所在層數
令人心碎,其中(2)(3)(4)(5)教材上都有對應類似代碼實現起來並不難,個人覺得難點主要在(1)中檢查輸入是否合法,即括號表示法合法性檢查這一塊內容。
我一共想到了以下幾種非法輸入(因個人能力有限,肯定還有沒想到的點,希望大家能指正包含)。
1.一對括號中逗號數超過兩個,例如A(B,C,D) ,非法
2. 形如 (B,C) 即在第一個左括號前少一個字符,非法
3.形如AA(B,C) ,即數據超過一個字符,非法。 注:本例中我默認數據元素只有一個字符
4.形如 A()) A)))((( ,類似左右括號不匹配,非法。
5.形如A(B,C)D ,類似錯誤
實現代碼如下
#include<bits/stdc++.h>
#define Max 100000
using namespace std;
char Tmax;//最大值節點
char Tmin;//最小值節點
int k1,k2;
struct node
{
char data;
node * lchild;
node * rchild;
};
bool CreateBTree(node * &b,string str)
{
stack<char>q; //判斷輸入合法性用的棧
bool flag=true;//是否合法標記
//bool zm=true;// 輸入節點名之後一定要跟一個左括號 如:AA非法
//bool jm=false;//在左括號前是否缺少節點元素判斷 如:(A,B) 非法 。false表示還未輸入數據元素,true表示已輸入節點元素
node *St[Max],*p;
int top=-1,k,j=0;
int Dnum=0;//逗號數量
char ch;
b=NULL;
ch=str[j];
while(ch!='\0' && flag)
{
switch(ch)
{
case '(':
//if(!jm)flag=false;
//jm=false;//輸入左括號後一定要跟一個節點元素 A(B,C)
if(q.empty()){cout<<"左括號前缺少數據元素"<<endl;flag=false;break;}//如果棧爲空,即左括號前沒有數據元素時,非法輸入
top++;
St[top]=p;
k=1;
q.push(ch);
Dnum=0;//輸入右括號後逗號數初始化0
break;
case ')':
//cout<<"test1"<<endl;
//if(q.empty())cout<<'1'<<endl;
top--;
while(!q.empty() && q.top()!='(')
{
if(q.top()==',' && Dnum>0)Dnum--;
q.pop();
}
if(q.empty()) //在獲取棧頂元素前一定要判斷棧是否爲空,如果爲空強行獲取棧頂元素程序會報錯
{
flag=false;
cout<<"左右括號不匹配"<<endl;
break;
}
else if(q.top()=='(')
{
q.pop();
}
break;
case ',':
k=2;
Dnum++;
q.push(ch);
if(Dnum>=2)
{
flag=false;
cout<<"逗號數量大於1個"<<endl;
}
break;
default:
p=new node;
p->data=ch;
p->lchild=p->rchild=NULL;
if(q.empty() || q.top()=='(' || q.top()==','||ch==',')//如果棧爲空或者棧頂元素爲'('將數據元素入棧
{
q.push(ch);
}
else //否則非法
{
flag=false;
cout<<"數據元素輸入過多(數據元素只允許一個字符)或某數據元素前一個字符不是左括號"<<endl;
//cout<<"test4"<<endl;
//cout<<q.top()<<endl;//test
//cout<<ch<<endl;//test
break;
}
if(b==NULL)
b=p;
else
{
switch(k)
{
case 1:St[top]->lchild=p;break;
case 2:St[top]->rchild=p;break;
}
}
}
if(flag==false)
{
//cout<<"輸入不合法,括號失配"<<endl;
return flag;
}
j++;
ch=str[j];
}
if(q.size()!=1)
{
flag=false;
cout<<"棧剩餘元素大於1,左右括號匹配失敗或其他未滿足格式情況"<<endl;
//int tmp=q.size(); test
//cout<<tmp<<endl;
}
return flag;
}
void PreOrder(node *b)//先序遍歷
{
if(b!=NULL)
{
cout<<b->data<<' ';
PreOrder(b->lchild);
PreOrder(b->rchild);
}
}
void InOrder(node *b)//中序遍歷
{
if(b!=NULL)
{
InOrder(b->lchild);
cout<<b->data<<' ';
InOrder(b->rchild);
}
}
void PostOrder(node *b)//後序遍歷
{
if(b!=NULL)
{
PostOrder(b->lchild);
PostOrder(b->rchild);
cout<<b->data<<' ';
}
}
int BTHeight(node *b)//獲得樹高度的函數
{
int lchildh,rchildh;
if(b==NULL)return 0;
else
{
lchildh=BTHeight(b->lchild);
rchildh=BTHeight(b->rchild);
return (lchildh>rchildh)?(lchildh+1):(rchildh+1);
}
}
void Dischild(node *b)//輸出葉子節點
{
if(b!=NULL)
{
if(b->lchild==NULL && b->rchild ==NULL)
cout<<b->data<<' ';
Dischild(b->lchild);
Dischild(b->rchild);
}
}
void getMaxMin(node *b,int k)
{
if(b==NULL) //空樹直接返回
return ;
else
{
char temp=b->data ;
k++;
if(temp>Tmax){Tmax=temp;k1=k;}
if(temp<Tmin){Tmin=temp;k2=k;}
getMaxMin(b->lchild ,k);
getMaxMin(b->rchild ,k);
}
}
int main()
{
string s;
bool flag;
node *b;
cin>>s;
while(!CreateBTree(b,s))
{
cout<<"輸入錯誤"<<endl;
cout<<endl;
flag=true;//合法標記重置
b=NULL;//指針重置
cin>>s;//重新輸入括號表達式
}
int height=BTHeight(b);
cout<<"先序遍歷:"<<endl;
PreOrder(b);
cout<<endl;
cout<<"中序遍歷:"<<endl;
InOrder(b);
cout<<endl;
cout<<"後序遍歷:"<<endl;
PostOrder(b);
cout<<endl;
cout<<"二叉樹的高度爲:"<<height<<endl;
cout<<"二叉樹的葉子節點爲:";
Dischild(b);
cout<<endl;
Tmax='0';
Tmin='z'+1;
getMaxMin(b,0);
cout<<"最大值節點爲:"<<Tmax<<" 其所在層數爲:"<<k1<<endl;
cout<<"最小值節點爲:"<<Tmin<<" 其所在層數爲:"<<k2<<endl;
return 0;
}
測試結果圖片