假設已經建立好二叉樹,知道二叉樹的前序序列,要輸出前序序列中第k(1<=k<=n)個結點中的數據應該怎麼操作?
此次測試用的是三層滿二叉樹,層次遍歷序列爲ABCDEFG
總體思路就是遞歸的去前序遍歷二叉樹,設置一個全局變量i,每過一個結點就+1當作計數器,等i==k時返回那個結點的值,思路很簡單但在遞歸這個問題上懵了。
建立二叉樹沿用之前【已知前序中序創建二叉樹】的代碼簡歷,經過幾次試錯……終於寫出了一個函數。
先貼上主函數:
void main(){
BiTree T;
char ch;
char A[7]={'A','B','D','E','C','F','G'};
char B[7]={'D','B','E','A','F','C','G'};
T=PreInCreat(A,B,0,6,0,6);//到此處均爲創建二叉樹
//ch=FINDK(T,4);
//cout<<"第N個結點數據是:"<<ch<<endl;//以K爲4
FindK(T,4);
system("pause");
}
(被//的兩條語句是用來配合課本方法輸出用的)①課本上的FINDK():
解釋在代碼註釋中
char FINDK(BiTree P,int k){
char ch;
if(P==NULL)
return '#';
i++;
if(i==k)
return P->data;//以上即爲前序遍歷中visit()部分,下面是造前序部分
ch=FINDK(P->lchild,4);
if(ch!='#')//當ch不再是#說明找到想要的數據了,在哪找到的無從得知,但現在已經傳到本層的ch這,而且要繼續傳上去,現在是傳遞鏈的一環
return ch;
ch=FINDK(P->rchild,4);//所找結點的父親結點接受數據時要用到這條語句,如本題中的B結點
return ch;//這條只是保證函數無論如何有返回,上一條return是判別語句
}
②自己寫的FindK():
void FindK(BiTree P,int k){
if(P!=NULL){
i++;
if(i==6)
cout<<P->data;//
FindK(P->lchild,k);
FindK(P->rchild,k);
}
}
我把函數設置成了一個不返回值的形式,在序號對上的時候直接打印出來,但事後想萬一要求不是打印而是要取到結點值,就要改一下,應該可以設置一個全局變量,在找到的時候把值給全局變量,就不用返回。
缺點是函數無論如何都會把二叉樹所有結點遍歷一邊纔會結束
對比一下之前錯誤的想法:(memo是計數器)
首先你寫了返回值char你就必須保證該函數有一個返回值,因此被迫寫了return '#',然後會發現這個return是沒有意義的,相當於每一層調用都返回了一個#,而data夾在衆多#中,書上的代碼返回#它是有ch承接而且要做判斷的。
發現了一些問題寫在代碼最後
完整代碼:
#include<iostream>
#include<stdlib.h>
using namespace std;
int i=0;
typedef struct BiNode{
char data;
struct BiNode *lchild,*rchild;
}BiNode,*BiTree;
BiTree PreInCreat(char A[],char B[],int l1,int h1,int l2,int h2){//創建二叉樹
int i,llen,rlen;
BiTree root;
root=(BiNode*)malloc(sizeof(BiNode));
root->data=A[l1];
for(i=l2;B[i]!=root->data;i++);
llen=i-l2;
rlen=h2-i;
if(llen)
root->lchild=PreInCreat(A,B,l1+1,l1+llen,l2,l2+llen-1);
else
root->lchild=NULL;
if(rlen)
root->rchild=PreInCreat(A,B,h1-rlen+1,h1,h2-rlen+1,h2);
else
root->rchild=NULL;
return root;
}
void FindK(BiTree P,int k){
if(P!=NULL){
i++;
if(i==6)
cout<<P->data;//以上即爲前序遍歷中visit()部分,下面是造前序部分
FindK(P->lchild,k);
FindK(P->rchild,k);
}
}
char FINDK(BiTree P,int k){
char ch;
if(P==NULL)
return '#';
i++;
if(i==k)
return P->data;
ch=FINDK(P->lchild,4);//以上即爲前序遍歷中visit()部分,下面是造前序部分
if(ch!='#')//當ch不再是#說明找到想要的數據了,在哪找到的無從得知,但現在在本層的ch這,要把他傳上去,現在是傳遞鏈的一環
return ch;
ch=FINDK(P->rchild,4);//所找結點的父親結點接受數據時要用到這條語句,如本題中的B結點
return ch;//這條只是保證函數無論如何有返回,上一條return是判別??
}
void main(){
BiTree T;
char ch;
char A[7]={'A','B','D','E','C','F','G'};
char B[7]={'D','B','E','A','F','C','G'};
T=PreInCreat(A,B,0,6,0,6);//到此處均爲創建二叉樹
//ch=FINDK(T,4);
//cout<<"第四個結點數據是:"<<ch<<endl;//以K爲4
FindK(T,4);
system("pause");
}
//發現問題:1.C++裏函數並不一定要有一個返回值,但你要記得你在定義函數的時候寫的是什麼,如果不返回了就記得寫成void
// 2.注意全局變量是要在#之後定義而不是在主函數中定義
// 3.函數只能返回一次值,你在中間某個部分執行了return,該層函數下面的部分就都不再執行了。看FINDK()