二叉樹有前序,中序,后序三種遍歷順序。初學者很容易混淆。記住以下兩個關鍵點就很好理解。
三種順序的共同點:左右的順序是不變的。
三種順序的不同點:所謂的前中后序,說的是root節(jié)點的位置在前,中,后。先序是root,左,右;中序是左,root,右;后序的順序是左,右,中?;谝陨蟽牲c記憶就非常簡單了。
遞歸序的后序遍歷,即自定義的代碼邏輯在左右遞歸結束后執(zhí)行。通用的偽代碼框架結構如下:
public static int recursion(TreeNode node){
if(node==null){
return 0;
}
//前序遍歷
//代碼邏輯
int left = recursion(node.left);
//中序遍歷 代碼邏輯
int right = recursion(node.left);
//后序遍歷
//代碼邏輯如下:
return left+right+node.data;
}
剛開始學遞歸,腦袋中一模擬方法中調用方法,腦袋就會炸鍋,瞬間感覺腦細胞不夠用了。其實可以換一個角度,放棄從root節(jié)點開始模擬,而是從最后一層葉子節(jié)點逆著模擬遞歸調用過程。
后序遍歷從執(zhí)行開始,代碼到 int left = recursion(node.left) 部分就會開啟新的壓棧,這個過程一直會持續(xù)到什么時候呢?答案是最終的葉子節(jié)點。
如果現(xiàn)在的入?yún)⑹侨~子節(jié)點,則node.left =null ,node.right=null 那么執(zhí)行遞歸函數(shù)后,都會返回0,即int left= 0,int right = 0;因為會判斷入?yún)閚ull,返回,不再繼續(xù)開啟新的堆棧了。
重點來了,跨過了前邊兩個坎兒
int left = recursion(node.left);
int right = recursion(node.left);
最終才會執(zhí)行到 return left+right+node.data部分,也就是自定義代碼這里。
葉子節(jié)點執(zhí)行完了,因為第一次調用這個方法的都是int left = recursion(node.left);所以會返回上一個堆棧記錄的地址,接著執(zhí)行上一個堆棧中的int right = recursion(node.left);以此往復,最終回到根結點root 再次執(zhí)行return left+right+node.data;
所以,后序遍歷的難點就是,只有到了葉子節(jié)點部分,才會完整執(zhí)行一次我們上邊寫的自定義代碼。其他部分都是只開堆棧,不執(zhí)行邏輯。
葉子節(jié)點時候,才會跳過左右繼續(xù)遞歸這兩個坎兒,第一次執(zhí)行返回操作。其他高一層級的調用,都是大爺,懶得要死,兒子不干完活兒返回結果,你休想叫醒他,讓他干一點活。但好處也是,一旦有返回結果了,他就自動執(zhí)行了。這就是后序遍歷的特點,高一級的依賴第低一級的返回結果。這么一說,有感覺了吧!
下邊這張圖展示了執(zhí)行順序

從root節(jié)點開始,一直執(zhí)行藍色的,直到最后一個藍色節(jié)點是null為止。返回到第二個藍色節(jié)點,執(zhí)行黃色點的遞歸方法,執(zhí)行完后,返回到當前的節(jié)點,即倒數(shù)第二個藍色節(jié)點,再返回,到達倒數(shù)第三個節(jié)點。。。以此類推
倒數(shù)第三個節(jié)點也是先執(zhí)行藍色,結束后回到黃色節(jié)點的方法體內,再執(zhí)行紅色遞歸調用,結束后再次回到黃色節(jié)點,執(zhí)行黃色節(jié)點的自定義代碼,之后再返回,達到倒數(shù)第三個節(jié)點