Java語言實現(xiàn)非遞歸實現(xiàn)樹的前中后序遍歷總結(jié)
前言
三種遍歷的遞歸寫法都很好寫,所以總結(jié)一下非遞歸寫法。
先貼一張圖復(fù)習(xí)一下三種遍歷方式就進(jìn)入正文啦~
【注:本文所有代碼實現(xiàn)中樹的結(jié)點定義如下:
public class Node { int val; Node left; Node right; Node parent; Node() {} Node(int val) { this.val = val; } }
1.前序遍歷
實現(xiàn)思路:
前序遍歷的順序是:根結(jié)點 -> 左孩子 -> 右孩子
借助一個棧結(jié)構(gòu)先將根結(jié)點壓入棧,然后循環(huán)每次取出棧頂元素,直到棧為空。如果當(dāng)前結(jié)點有右孩子就先將右孩子壓入棧中,如果當(dāng)前結(jié)點有左孩子就將左孩子壓入棧中,這里注意順序,因為棧的結(jié)構(gòu)是先進(jìn)后出的,為了保證先遍歷到左孩子就應(yīng)該后壓左孩子~
代碼實現(xiàn):
【代碼使用直接輸出的方式打印中序遍歷結(jié)果,也可以放入一個list中存儲~】
public void preOrder(Node head) { System.out.println("pre-order:"); if(head != null) { Stack<Node> stack = new Stack<>(); stack.push(head); while(!stack.isEmpty()) { head = stack.pop(); System.out.print(head.val + " "); if (head.right != null) stack.push(head.right); if (head.left != null) stack.push(head.left); } } }
2.中序遍歷
實現(xiàn)思路:
中序遍歷的順序:左孩子 -> 根結(jié)點 -> 右孩子
借助棧結(jié)構(gòu),將當(dāng)前結(jié)點的左孩子依次入棧直到?jīng)]有左孩子了就彈出棧頂元素并打印,如果彈出的結(jié)點有右孩子就將右孩子的左邊界依次入棧,循環(huán)…
比如文章開始的那個圖中,先將A,B,D依次入棧,此時棧頂元素是D,彈出并打印,D結(jié)點有右孩子,將D的右孩子的左邊界依次入棧,壓入結(jié)點G,結(jié)點G沒有左孩子所以彈出并打印G,此時棧頂元素是B,循環(huán)…直到棧中為空且當(dāng)前結(jié)點為空時遍歷結(jié)束。
代碼實現(xiàn):
public static void inOrderTraverse(Node head) { System.out.println("in-order:"); if(head != null) { Stack<Node> stack = new Stack<>(); while(!stack.isEmpty() || head != null) { if(head != null) { // 當(dāng)前節(jié)點不為空, 將自己壓進(jìn)棧并將自己的左孩子作為當(dāng)前節(jié)點(壓入左邊界) stack.push(head); head = head.left; }else { // 當(dāng)前節(jié)點為空(沒有左孩子了), 將棧頂元素彈出作為當(dāng)前節(jié)點, 并將當(dāng)前節(jié)點的右孩子壓進(jìn)棧 head = stack.pop(); System.out.print(head.val + " "); head = head.right; } } } }
3.后序遍歷
實現(xiàn)思路:
后序遍歷的順序:左孩子 -> 右孩子 -> 根結(jié)點
仔細(xì)想一下,打印每個結(jié)點需要訪問根結(jié)點三次,先從根結(jié)點開始找到左孩子,返回再找到右孩子,再返回到根結(jié)點,需要訪問根結(jié)點三次,直接按照當(dāng)前順序進(jìn)行遍歷不知如何下手,那么我們可以換一個角度去考慮。
棧結(jié)構(gòu)是先進(jìn)后出的,那我們不妨借助一個棧先存儲 根結(jié)點 -> 右孩子 -> 左孩子 的結(jié)果,再將其依次彈出就是后序遍歷的順序了。
那實現(xiàn) 根結(jié)點 -> 右孩子 -> 左孩子 的方法就很簡單了,回憶一下剛才說的前序遍歷的方式,前序遍歷是先要左孩子,就后壓入左孩子,反之,將前序遍歷的邏輯改寫為:彈出每個棧頂結(jié)點作為當(dāng)前結(jié)點并存儲到一個輔助棧中,如果當(dāng)前結(jié)點有左孩子就先壓入左孩子,如果有右孩子就后壓入右孩子,每次取棧頂彈出到輔助棧中。最后將得到的輔助棧中元素依次彈出得到的就是后序遍歷的結(jié)果。
代碼實現(xiàn):
public static void posOrderTraverse(Node head) { System.out.println("pos-order"); if(head != null) { Stack<Node> stack1 = new Stack<>(); Stack<Node> stack2 = new Stack<>(); // 輔助棧,存儲 根 -> 右 -> 左 的結(jié)果 stack1.push(head); while(!stack1.isEmpty()) { head = stack1.pop(); stack2.push(head); // 有左孩子就先壓入左孩子 if(head.left != null) stack1.push(head.left); // 有右孩子就后壓入右孩子 if(head.right != null) stack1.push(head.right); } // 逆序打印 根 -> 右 -> 左 的結(jié)果,就是后序遍歷的結(jié)果 while(!stack2.isEmpty()) System.out.print(stack2.pop().val + " "); } }
總結(jié)
以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,謝謝大家對腳本之家的支持。如果你想了解更多相關(guān)內(nèi)容請查看下面相關(guān)鏈接
相關(guān)文章
SpringBoot實現(xiàn)對超大文件進(jìn)行異步壓縮下載的使用示例
在Web應(yīng)用中,文件下載功能是一個常見的需求,本文介紹了SpringBoot實現(xiàn)對超大文件進(jìn)行異步壓縮下載的使用示例,具有一定的參考價值,感興趣的可以了解一下,2023-09-09Maven中錯誤使用parent.relativePath導(dǎo)致構(gòu)建失敗問題
這篇文章主要介紹了Maven中錯誤使用parent.relativePath導(dǎo)致構(gòu)建失敗問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-08-08Gradle環(huán)境下導(dǎo)出Swagger為PDF的步驟詳解
這篇文章主要介紹了Gradle環(huán)境下導(dǎo)出Swagger為PDF的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧2019-06-06解決@CachePut設(shè)置的key值無法與@CacheValue的值匹配問題
這篇文章主要介紹了解決@CachePut設(shè)置的key的值無法與@CacheValue的值匹配問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-12-12eclipse maven maven-archetype-webapp 創(chuàng)建失敗問題解決
這篇文章主要介紹了eclipse maven maven-archetype-webapp 創(chuàng)建失敗問題解決的相關(guān)資料,需要的朋友可以參考下2016-12-12