由於遞迴演算法相對於非遞迴演算法來說效率通常都會更低,遞迴演算法會有更多的資源需要壓棧和出棧操作(不僅僅是引數,還有函式位址等)由於編譯器對附加的一些棧保護機制會導致遞迴執行的更加低效,使用迴圈代替遞迴演算法,通常可以獲得更好的執行效率和空間效率,在二叉樹層次較深的情況下,採用非遞迴方式遍歷能夠有效的提公升遍歷的效能。
二叉樹的非遞迴遍歷分為三種:先序非遞迴遍歷,中序非遞迴遍歷和後續非遞迴遍歷。這和遞迴遍歷的結果是一樣的,區別只是在於採用了迴圈結構。
先序非遞迴遍歷
採用輔助資料結構棧來實現,先序遍歷是按照先根,後左子樹,再右子樹的順序進行遞迴訪問的。由於棧是先入後出的,所以入棧順序為先右孩子後左孩子。
非遞迴的演算法是先將根結點入棧,棧不為空時:根結點出棧並訪問,然後將右孩子入棧,再將左孩子入棧;左孩子出棧並訪問,它的孩子也是按照先右後左順序分別入棧,如此往復直至棧為空結束。**如下:
void
preordernorecursion
(btnode* p)
}}
先序非遞迴根結點先入棧,然後以棧不為空為迴圈判定條件。中序非遞迴遍歷
輔助資料結構仍採用棧,為實現左-根-右的訪問順序,中序遍歷的第乙個結點為最左邊的那個結點,據此,可以先從根結點開始入棧,沿著最左邊的那條分支依次入棧,這樣棧頂元素就是中序遍歷中的第乙個結點了。
接下來需要做的是當棧中元素出棧並被訪問後,若該結點有右孩子怎麼辦?這時,從該結點的右孩子開始,按照最左邊分支將結點依次入棧,出棧時進行訪問。由此往復,直至結束。**如下:
void
inordernorecursion
(btnode* p)
if(top!=-1
)//出棧時temp指向出棧結點的右孩子,進行下一輪迴圈
}}
中序非遞迴遍歷根結點先不入棧,迴圈判定條件有兩個。後序非遞迴遍歷
這裡列出一種比較好理解的後續非遞迴遍歷,它的思路可以看下面的例子
對上圖中的a,b,c三個結點來講:
先序遍歷為:a,b,c
後序遍歷為:b,c,a
二者之間的聯絡在於,如果將先序遍歷順序的根-左-右改為根-右-左,即交換訪問次序,遍歷結果為a,c,b,然後將其結果逆序,得b,c,a。這剛好是後序遍歷的結果。
對上圖中的所有結點來講:
先序遍歷為:a,b,d,e,c,f
交換次序後的結果為:a,c,f,b,e,d
再逆序:d,e,b,f,c,a
而後序遍歷的結果也為:d,e,b,f,c,a
由此可得:
先序+交換+逆序=後序
void
postordernorecursion
(btnode* p)
while
(top2 !=-1
)//再逆序
std::cout << stack2[top2--]-
>data <<
' ';
//訪問棧2中的資料
}}
完整示例
關於二叉樹非遞迴遍歷的完整**如下:
#include
typedef
struct btnode
btnode;
btnode*
initial
(char
* ele,
int num)
;//用陣列初始化一棵樹
void
level
(btnode* p)
;//層序遍歷
void
preordernorecursion
(btnode* p)
;//先序非遞迴遍歷
void
inordernorecursion
(btnode* p)
;//中序非遞迴遍歷
void
postordernorecursion
(btnode* p)
;//後序非遞迴遍歷
intmain()
; btnode* p =
initial
(data,6)
; cout <<
"先序非遞迴遍歷: "
;preordernorecursion
(p);
cout << endl;
cout <<
"中序非遞迴遍歷: "
;inordernorecursion
(p);
cout << endl;
cout <<
"後序非遞迴遍歷: "
;postordernorecursion
(p);
cout << endl;
cout <<
"層序遍歷: "
;level
(p);
cout << endl;
return0;
}btnode*
initial
(char
* ele,
int num)
i =0;
while
(i < num/2)
//通過完全二叉樹的順序儲存來建立樹的結構
for(i =
0; i < num; i++
)//對樹中的每個結點賦值
temp[i]
.data = ele[i]
;return temp;
}void
preordernorecursion
(btnode* p)}}
void
inordernorecursion
(btnode* p)
if(top!=-1
)//出棧時temp指向出棧結點的右孩子,進行下一輪迴圈}}
void
postordernorecursion
(btnode* p)
while
(top2 !=-1
) std::cout << stack2[top2--]-
>data <<
' ';}}
void
level
(btnode* p)
if(que[front]
->rc !=
null)}
}}
二叉樹遍歷(遞迴 非遞迴)
二叉樹以及對二叉樹的三種遍歷 先根,中根,後根 的遞迴遍歷演算法實現,以及先根遍歷的非遞迴實現。node public class node public node left public node right public object value 遍歷訪問操作介面 public inte ce ...
二叉樹非遞迴遍歷
二叉樹非遞迴遍歷的幾個要點 1 不管前序 中序還是後序,它們的遍歷路線 或者說是回溯路線,先沿左邊一直走到盡頭,然後回溯到某節點,並跳轉到該節點的右孩子 如果有的話 然後又沿著這個有孩子的左邊一直走到盡頭 都是一樣的。2 明確每次回溯的目的。比如,前序回溯的目的是為了訪問右子樹 中序回溯的目的是為了...
非遞迴遍歷二叉樹
中序遞迴遍歷 void inordertrvdigui node pnode 然而,當樹的深度很大 比如16 時 假設為滿二叉樹 樹的節點數為 2 0 2 1 2 2 2 15 2 16 65536,遍歷整個二叉樹意味著有65536次函式呼叫,這將極大地增加程式執行時間。這時,應該採取非遞迴便利二叉...