二叉樹遍歷的非遞迴實現

2022-04-06 01:07:57 字數 3509 閱讀 8729

二叉樹的構建使用的是鍊錶的形式,每個節點中既包含了根節點的元素,也包含了指向左右孩子的指標,實際可以看成乙個二維的線性結構。

二叉樹的遍歷實質就是就二維變為一維的過程。

前序遍歷的遞迴思想是:

首先訪問根節點

然後以左子樹為根節點遞迴呼叫遍歷函式,(這樣就沿著樹的最左邊的分支遍歷到最左邊的葉子節點)

接著以右子樹為根節點遞迴呼叫遍歷函式,(這樣就逐層回到呼叫的根節點,然後遞迴根節點的右節點)

中序與後序的遞迴遍歷思想一樣,只是訪問根節點的先後順序不一樣

以中序遍歷為例實現遞迴遍歷

templte

void preorder(binaryttreenode*t)

if(t!=null)

visit(t);                                //訪問根節點

preorder(t->leftchild);       //前序遍歷左子樹

preorder(t->rightchild);    //前序遍歷右子樹

非遞迴實現二叉樹的思想是使用堆疊來實現的

實際上,無論是前序、中序還是後序遍歷,其在樹中所走的路勁的順序都是一樣的。都是先指到根節點,然後指到左子樹最後指到右子樹,只是不同的遍歷,在訪問左右子樹和根節點的順序不同而已。

那麼就可以使用堆疊來實現非遞迴的遍歷

首先當指到根節點時,將其壓入堆疊,然後指向其左子樹,如果左子樹非空,也將其入棧,這樣就到達最左邊的葉子節點

然後從棧中依次取出每個「根節點」

最後再指向這些「根節點」的右子樹

以上根節點打雙引號是因為實際上是將左右節點在某個位子看成了根節點,實際上在遍歷構成中,不同的根節點也正是這些左右節點,利用堆疊就是使各左右節點在合適的位置成為根節點。

對於不同的遍歷,只是訪問訪問「根節點」的順序不同,便可得到不同遍歷的非遞迴遍歷方法如下:

前序遍歷:

當遇到乙個節點就訪問它並將其壓入棧中,然後遍歷其左子樹

當左子樹遍歷結束後,從棧頂彈出這個節點

然後指向其右子樹再按前序遍歷

其實現如下:

void preorder(binarytreenodet)

binarytreenode tmp=t;

stack s=creatstack(size);  //偽**,建立乙個長度為size的棧

while(!t.empty || !empty(s))  //只要樹和棧非空

while(!t.empty)      //一直向左並將沿途的節點壓入棧中

visit(t);         //訪問t

push(s,t);     //將t壓入棧

t=t->leftchild;

if(empty(s))

t=pop(s);   //將節點彈出堆疊

t=t->rightchild;   //轉向右子樹

中序遍歷:

當遇到乙個節點就將其壓入棧中,然後遍歷其左子樹

當左子樹遍歷結束後,從棧頂彈出這個節點並訪問它

然後指向其右子樹再按中序遍歷

void inorder(binarytreenodet)

binarytreenode tmp=t;

stack s=creatstack(size);  //偽**,建立乙個長度為size的棧

while(!t.empty || !empty(s))  //只要樹和棧非空

while(!t.empty)      //一直向左並將沿途的節點壓入棧中

push(s,t);     //將t壓入棧

t=t->leftchild;

if(empty(s))

t=pop(s);   //將節點彈出堆疊

visit(t);         //訪問t

t=t->rightchild;   //轉向右子樹

後序遍歷:

後序遍歷的非遞迴實現是三種遍歷方式中最難的一種。在前兩種遍歷中,左子樹都是在根節點之前可以遍歷到,而右子樹都是在根節點後才遍歷。而在後序遍歷中,要保證左孩子和右孩子都已被訪問並且左孩子在右孩子前訪問才能訪問根結點,這就為流程的控制帶來了難題。 

一種思路如下:要保證根結點在左孩子和右孩子訪問之後才能訪問,因此對於任一結點p,先將其入棧。如果p不存在左孩子和右孩子,則可以直接訪問它;或者p存在左孩子或者右孩子,但是其左孩子和右孩子都已被訪問過了(通過設定被訪問標記來判斷),則同樣可以直接訪問該結點。若非上述兩種情況,則將p的右孩子和左孩子依次入棧,這樣就保證了每次取棧頂元素的時候,左孩子在右孩子前面被訪問,左孩子和右孩子都在根結點前面被訪問。

void inorder(binarytreenodet)

binarytreenode tmp=t;

stack s=creatstack(size);  //偽**,建立乙個長度為size的棧

while(!t.empty || !empty(s))  //只要樹和棧非空

while(!t )     //t不是空節點

{ //一直向左並將沿途的節點壓入棧中

push(s,t);     //將t壓入棧

if(!t->rightchild.isvisited()&& t->rightchild)    //t存在未被訪問過的右節點

t=t->rightchild;  

push(s,t);     //將t的右節點壓入棧

t.isvisited();  //將t的右節點壓設為被訪問過

if(!t->leftchild.isvisited()&& t->lefttchild)    //t存在未被訪問過的左節點

t=t->rightchild;  

else

t=null;

if(empty(s))

t=pop(s);   //將節點彈出堆疊

visit(t);         //訪問t

//t=t->rightchild;   //轉向右子樹

層次遍歷:

層次遍歷是逐層訪問,每一層從左自右逐個訪問,這種實現方法可以使用佇列來實現。

從根節點開始入隊

然後從隊首取出元素,並訪問該元素所指節點

然後判斷該節點的左右孩子是否為空,並按先後順序將非空節點入隊

void  levelorder( binarytreenode*t)

queue q;  //建立佇列

binarytreenodetree;

if(!t)

return;   //如果樹為空,則直接返回

q=createqueue(size);  //偽**,建立長度為size的佇列

addq(q,t);  //將tree入隊

while(!q.empty)  //佇列非空時

tree=q.top;   //隊首元素出隊

q.pop();   //刪除隊首

/*將非空子樹入隊*/

if(tree.leftchild)  addq(q,tree.leftchild);

if(tree.leftchild)  addq(q,tree.leftchild);

二叉樹遍歷 遞迴 非遞迴實現

先序遍歷中序遍歷 後序遍歷 根結點 左子樹 右子樹 左子樹 根子樹 右子樹 左子樹 右子樹 根結點 先序遍歷 void preorder btree t 中序遍歷 void inorder btree t 後序遍歷 void postorder btree t 遞迴 recursion 就是子程式 ...

二叉樹遍歷的非遞迴實現

最近在看二叉樹的非遞迴呼叫,書上 寫的蠻清楚,但是一些細節需要深入的思考才會理解掌握。先根遍歷比較簡單,不斷的尋找根的左節點,並輸出,同時將對應節點的右節點壓入棧中,直到左節點為空,將棧頂元素出棧,作為根重複上述操作,直到棧為空。中根遍歷,將根節點左節點,左節點的左節點.依次入棧,直到最後乙個無左節...

遍歷二叉樹的非遞迴實現

對於二叉樹來說,只要按照下面的模板可以很容易地實現先序 中序和後序的遞迴遍歷二叉樹。void visit treenode node 使用遞迴可以使 變得簡潔,明了。我們不用考慮計算機底層的遞迴工作棧是怎麼實現的,只要寫好遞迴式,給出遞迴終止條件,就可以把剩餘的計算工作交給計算機去執行。所以說遞迴是...