一、實驗目的
(1)掌握二叉樹的邏輯結構;
(2)掌握二叉樹的二叉鏈表存儲結構;
(3)掌握基於二叉鏈表存儲的二叉樹的遍歷操作的實現。
二、實驗內容
(1)建立一棵含有n個結點的二叉樹,採用二叉鏈表存儲;
(2)前序(或中序、後序)遍歷該二叉樹。
(3)統計該二叉樹中葉子個數。
(4)統計該二叉樹中結點個數。
(5)求該二叉樹的深度。
要求:
(1)設計菜單,根據菜單提示進行操作。
(2)按先序遍歷序列創建二叉樹的二叉鏈表。
注:二叉樹的遍歷一般採用遞歸算法,只要涉及到遞歸,一定會使用堆棧來實現。雖然在程序中看不到具體的堆棧,但可以通過觀察函數調用的關係來理解認識堆棧。堆棧是實現二叉樹遍歷的最基本的數據結構。
三、算法設計
1、先序遍歷遞歸建立二叉樹
步驟
- 掃描字符序列, 讀入字符
ch
。 - 如果ch是一個
"#"
字符, 則表明該二叉樹爲空樹, 即BT
爲NULL
; 3. 否則執行以下操作:
申請一個結點空間BT
;
將ch
賦給BT-> data
;
遞歸創建BT
的左子樹;
遞歸創建BT
的右子樹;
算法
void CreateBiTree(BiTree &BT){
if(ch=='#')
BT = NULL;
else{
BT = new BiTNode;
BT->data = ch;
CreateBiTree (BT->Lchild);
CreateBiTree (BT->Rchild);
}
}
2、遍歷二叉樹
2.1 先序遍歷
步驟
若二叉樹爲空,則空操作;
否則 :
- 訪問根結點;
- 先序遍歷左子樹;
- 先序遍歷右子樹
算法
void PreOrder(BiTree &BT){
if(BT){
Visit(BT);
PreOrder(BT->Lchild);
PreOrder(BT->Rchild);
}
}
2.2 中序遍歷
步驟
若二叉樹爲空,則空操作;
否則
- 中序遍歷左子樹;
- 訪問根結點;
- 中序遍歷右子樹。
算法
void InOrder(BiTree BT){
if(BT){
InOrder(BT->Lchild);
Visit(BT);
InOrder(BT->Rchild);
}
}
2.3 後序遍歷
步驟
若二叉樹爲空,則空操作;
否則
- 後序遍歷左子樹;
- 後序遍歷右子樹;
- 訪問根結點。
算法
void PostOrder(BiTree BT){
if(BT){
PostOrder(BT->Lchild);
PostOrder(BT->Rchild);
Visit(BT);
}
}
3、統計二叉樹葉子結點個數
步驟
- 如果是空樹,則結點個數爲 0;
- 如果只有根結點則就1個葉子結點;
- 否則,結點個數爲左子樹的葉子結點個數加上右子樹的葉子結點個數。
算法
int LeafCount(BiTree &BT){
if(!BT)
return ERROR;
if(!BT->Lchild&&!BT->Rchild)
return OK;
return(LeafCount(BT->Lchild)+LeafCount(BT->Rchild));
}
4、交換二叉樹左右子樹
算法
void ChangeLR(BiTree BT){
BiTree St;
if(BT){
ChangeLR(BT->Lchild);
ChangeLR(BT->Rchild);
St = BT->Lchild;
BT->Lchild = BT->Rchild;
BT->Rchild = St;
}
}
5、統計二叉樹中結點的總數
步驟
- 如果是空樹,則結點個數爲 0;
- 否則,結點個數爲左子樹的結點個數加上右子樹的結點個數再加上 1 。
算法
int NodeCount(BiTree BT){
if(!BT)
return ERROR;
else
return(NodeCount(BT->Lchild)+NodeCount(BT->Rchild)+1);
}
6、求二叉樹的深度
步驟
如果是空樹,遞歸結束,深度爲0;
否則執行以下操作:
- 遞歸計算左子樹的深度記爲m;
- 遞歸計算右子樹的深度記爲n;
- 如果 m 大於 n, 二叉樹的深度爲 m+1, 否則爲 n+1。
算法
int Depth(BiTree BT){
int h1,h2;
if(BT==NULL)
return ERROR;
h1 = Depth(BT->Lchild);
h2 = Depth(BT->Rchild);
if(h1>h2)
return(h1 + 1);
else
return(h2 + 1);
}
四、運行結果
五、代碼實現
#include<stdio.h>
#include<stdlib.h>
#define ERROR 0
#define OK 1
#define TElemType char
typedef struct BiTNode{
TElemType data;
struct BiTNode *Lchild,*Rchild;
}BiTNode,*BiTree;
//顯示根結點
void Visit(BiTree BT){
printf("%c",BT->data);
}
//先序遍歷
void PreOrder(BiTree BT){
if(BT){
Visit(BT);
PreOrder(BT->Lchild);
PreOrder(BT->Rchild);
}
}
//中序遍歷
void InOrder(BiTree BT){
if(BT){
InOrder(BT->Lchild);
Visit(BT);
InOrder(BT->Rchild);
}
}
//後序遍歷
void PostOrder(BiTree BT){
if(BT){
PostOrder(BT->Lchild);
PostOrder(BT->Rchild);
Visit(BT);
}
}
//按先序次序輸入二叉樹中結點的值(一個字符),創建二叉鏈表表示的二叉樹
void CreateBiTree(BiTree &BT){
char ch;
scanf("%c",&ch);
if(ch!='#'){
BT =new BiTNode;
// if(!BT)
// exit(-1);
BT->data = ch;
CreateBiTree(BT->Lchild);
CreateBiTree(BT->Rchild);
}
else{
BT = NULL;
}
}
//統計二叉樹中葉子結點的個數
int LeafCount(BiTree &BT){
if(!BT)
return ERROR;
if(!BT->Lchild&&!BT->Rchild)
return OK;
return(LeafCount(BT->Lchild)+LeafCount(BT->Rchild));
}
//交換二叉樹的左右子樹
void ChangeLR(BiTree BT){
BiTree St;
if(BT){
ChangeLR(BT->Lchild);
ChangeLR(BT->Rchild);
St = BT->Lchild;
BT->Lchild = BT->Rchild;
BT->Rchild = St;
}
}
//統計二叉樹中結點的總數
int NodeCount(BiTree BT){
if(!BT)
return ERROR;
else
return(NodeCount(BT->Lchild)+NodeCount(BT->Rchild)+1);
}
//求二叉樹的深度
int Depth(BiTree BT){
int h1,h2;
if(BT==NULL)
return ERROR;
h1 = Depth(BT->Lchild);
h2 = Depth(BT->Rchild);
if(h1>h2)
return(h1 + 1);
else
return(h2 + 1);
}
//銷燬二叉樹
void DestroyBiTree(BiTree BT){
if(!BT)return;
DestroyBiTree(BT->Lchild);
DestroyBiTree(BT->Rchild);
delete BT;
}
void Showmenu(){
printf("\n");
printf(" --二叉樹基本操作運算-- \n");
printf("******************************\n");
printf("* 1---建立二叉樹 *\n");
printf("* 2---先序遍歷 *\n");
printf("* 3---中序遍歷 *\n");
printf("* 4---後序遍歷 *\n");
printf("* 5---統計葉子數 *\n");
printf("* 6---統計結點數 *\n");
printf("* 7---求二叉樹深度 *\n");
printf("* 8---交換左右子樹 *\n");
printf("* 0---退出 *\n");
printf("*****************************\n");
printf("請選擇菜單號(0-8):");
}
void binaryOP(){
BiTree BT;
int count = 0;
int choice;
while(choice){
Showmenu();
scanf("%d",&choice);
switch(choice){
case 1:
printf("按先序輸入二叉樹結點序列:\n");//以#結束
CreateBiTree(BT);
printf("二叉樹建立成功!\n");
break;
case 2:
if(BT == NULL){
printf("空樹!\n");
}
else{
printf("先序遍歷序列爲:");
PreOrder(BT);
}
break;
case 3:
if(BT == NULL){
printf("空樹!\n");
}
else{
printf("中序遍歷序列爲:");
InOrder(BT);
}
break;
case 4:
if(BT == NULL){
printf("空樹!\n");
}
else{
printf("後序遍歷序列爲:");
PostOrder(BT);
}
break;
case 5:
count = LeafCount(BT);
printf("該二叉樹有%d個葉子結點。\n",count);
break;
case 6:
count = NodeCount(BT);
printf("該二叉樹有%d個結點。\n",count);
break;
case 7:
printf("該二叉樹的深度爲%d !\n",Depth(BT));
break;
case 8:
ChangeLR(BT);
printf("交換成功!\n");
printf("先序序列爲:\n");
PreOrder(BT);
break;
case 0:
printf("程序結束!\n");
break;
}
}
}
int main(){
binaryOP();
return 0;
}
作者文壇寫於 2020年5月21日