基本概念
- 前序遍歷:先訪問根節點,再訪問左子節點,最后訪問右子節點
- 中序遍歷:先訪問左子節點,再訪問跟節點,最后訪問右子節點
- 后序遍歷:先訪問左子節點,再訪問右子節點,最好訪問根節點
前序遍歷
要想用非遞歸的方式解決問題,幾乎都是采用棧的方式解決。前序遍歷是先訪問根節點,再訪問左子節點,最后訪問右子節點,對應圖中順序1->2->4->5->3->6->7.所以我們可以采用以下方式來做:
- 假設cur=head,將cur入棧
- 不斷從棧中彈出棧頂節點,然后把右子節點和左子節點放入棧中(因為先訪問左子節點,棧為先進后出的數據結構,所以先放左子節點)
- 當棧不為空,不斷重復上一步驟
代碼如下
public void preOrderUnRecur(Node node){
System.out.println("非遞歸前序遍歷");
if (node == null) return;
Stack<Node> stack = new Stack<>();
stack.push(node);
while (!stack.empty()){
Node curNode = stack.pop();
System.out.print(curNode.value+" ");
if (curNode.right != null) stack.push(curNode.right);
if (curNode.left != null) stack.push(curNode.left);
}
System.out.println();
}
中序遍歷
中序遍歷的順序是先左子節點,再當前節點,再右子節點,對應圖中4->2->5->1->6->3->7.解題思路如下
- 初始化cur=head
- 將cur入棧,不斷將cur=cur.left(不斷取左子節點),重復當前過程
- 如果發現cur為空,則說明已經訪問到“最左“節點,出棧並打印當前節點的值,將其右子節點賦值給cur,重復上一步
代碼如下:
public void inOrderUnRecur(Node node){
if (node == null) return;
Stack<Node> stack = new Stack<>();
while (!stack.empty() || node != null){
if (node != null){
stack.push(node);
node = node.left;
}else {
node = stack.pop();
System.out.println(node.value);
node = node.right;
}
}
}
后序遍歷
后序遍歷的訪問順序為先左子節點,再右子節點,最后訪問當前節點,對應於圖中的4->5->2->6->7->3->1,后序遍歷比較難,我這里提供一種雙棧的解決思路。想一下怎么能做到先左再右最后中呢?要想做到這一點,根節點要在棧底,然后是右子節點,最后是左子節點。我們可以采用如下方式做到這一點
- 申請兩個棧s1,s2,將頭節點壓入s1
- 從s1中彈出節點cur依次將cur的做孩子右孩子壓入s1,同時將cur壓入棧s2中
- 最后s2的棧即為訪問順序,不斷彈出打印即可
代碼如下
public void posOrderUnRecur(Node node){
Stack<Node> stack1 = new Stack<>();
Stack<Node> stack2 = new Stack<>();
stack1.push(node);
while (!stack1.empty()){
node = stack1.pop();
stack2.push(node);
if (node.left != null){
stack1.push(node.left);
}
if (node.right != null){
stack1.push(node.right);
}
}
while (!stack2.empty()){
System.out.println(stack2.pop().value);
}
}