LeetCode刷題Easy篇二叉樹遍歷
題目
二叉樹的前序,中序,後序遍歷
Depth First Traversals:
(a) Inorder (Left, Root, Right) : 4 2 5 1 3
(b) Preorder (Root, Left, Right) : 1 2 4 5 3
(c) Postorder (Left, Right, Root) : 4 5 2 3 1
Breadth First or Level Order Traversal : 1 2 3 4 5
https://www.geeksforgeeks.org/tree-traversals-inorder-preorder-and-postorder/
遞迴解法
/* Given a binary tree, print its nodes according to the "bottom-up" postorder traversal. */ void printPostorder(Node node) { if (node == null) return; // first recur on left subtree printPostorder(node.left); // then recur on right subtree printPostorder(node.right); // now deal with the node System.out.print(node.key + " "); } /* Given a binary tree, print its nodes in inorder*/ void printInorder(Node node) { if (node == null) return; /* first recur on left child */ printInorder(node.left); /* then print the data of node */ System.out.print(node.key + " "); /* now recur on right child */ printInorder(node.right); } /* Given a binary tree, print its nodes in preorder*/ void printPreorder(Node node) { if (node == null) return; /* first print data of node */ System.out.print(node.key + " "); /* then recur on left sutree */ printPreorder(node.left); /* now recur on right subtree */ printPreorder(node.right); }
前序非遞迴解法
我的嘗試:
我的嘗試問題有問題,我在while迴圈的時候把左側節點都存入list,我以為這些左側節點都是root,只要從stack取出來,然後新增上右側節點就可以了,其實不對,比如在 1-null-2-3,情況下,加入list的節點是右側節點2,不是左側節點,因為沒有左側節點。如下圖所示:
所以這個情況下, 我的輸出結果多一個2.
/** * Definition for a binary tree node. * public class TreeNode { * int val; * TreeNode left; * TreeNode right; * TreeNode(int x) { val = x; } * } */ class Solution { public List<Integer> preorderTraversal(TreeNode root) { List<Integer> list=new ArrayList(); Stack<TreeNode> stack=new Stack<TreeNode>(); TreeNode curr=root; while(curr!=null){ list.add(curr.val); stack.push(curr); //[1,null,2,3],left不存在情況無法cover if(curr.left!=null){ curr=curr.left; } else{ curr=curr.right; } } while(stack.empty()==false){ TreeNode tmpNode=(TreeNode)stack.pop(); TreeNode tmpRight=tmpNode.right; if(tmpRight!=null){ list.add(tmpRight.val); } } return list; } }
正確解法:
在重新整理思路後,寫了如下演算法,一次通過leetcode測試,為自己喝彩!!!
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> list=new ArrayList();
if(root==null) return list;
Stack<TreeNode> stack=new Stack<TreeNode>();
TreeNode curr=root;
list.add(curr.val);
if(curr.right!=null){
stack.push(curr.right);
}
if(curr.left!=null){
stack.push(curr.left);
}
while(stack.empty()==false){
TreeNode tmpNode=(TreeNode)stack.pop();
list.add(tmpNode.val);
if(tmpNode.right!=null){
stack.push(tmpNode.right);
}
if(tmpNode.left!=null){
stack.push(tmpNode.left);
}
}
return list;
}
}
我寫的程式碼可以優化一下,第一段判斷右左是否存在,並且入stack的操作,跟後面孩子節點的程式碼其實是重複的 ,優化整合一下:
1. 判斷根節點是否為空,為空,返回空list,不為空,入stack
2. 迴圈從stack取出stack頂部元素,先訪問該node,然後判斷是否有左右節點,如果有,先入右,後入左。直到為空
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> list=new ArrayList();
if(root==null) return list;
Stack<TreeNode> stack=new Stack<TreeNode>();
stack.push(root);
while(stack.empty()==false){
TreeNode tmpNode=(TreeNode)stack.pop();
list.add(tmpNode.val);
if(tmpNode.right!=null){
stack.push(tmpNode.right);
}
if(tmpNode.left!=null){
stack.push(tmpNode.left);
}
}
return list;
}
public List<Integer> postorderTraversal(TreeNode root) {
//不可以寫list,方法addFirst找不到
LinkedList<Integer> list=new LinkedList<>();
Stack<TreeNode> stack=new Stack();
if(root==null){
return list;
}
stack.push(root);
while(!stack.isEmpty()){
TreeNode treeNode=stack.pop();
//為了反轉list,所以利用linkedlist的addFirst介面
list.addFirst(treeNode.val);
if(treeNode.left!=null){
stack.push(treeNode.left);
}
if(treeNode.right!=null){
stack.push(treeNode.right);
}
}
return list;
}
}
中序非遞迴解法
中序遍歷,寫對了兩個關鍵部分程式碼:
一個是指標curr從root開始,一直左側遍歷到底,直到為空,第二個是stack彈出元素,訪問。但是不知道怎麼處理右側節點。看了solution後,恍然大悟。修改curr指向curr.right。
整理思路後,寫程式碼如下:
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public List<Integer> inorderTraversal(TreeNode root) {
Stack<TreeNode> stack=new Stack();
List<Integer> list=new ArrayList();
TreeNode curr=root;
while(curr!=null||!stack.isEmpty()){
//如果右子樹不為空,又是從左側一路到底
while(curr!=null){
stack.push(curr);
curr=curr.left;
}
curr=stack.pop();
list.add(curr.val);
//我的程式碼只是少這個關鍵一行,處理右子樹
curr=curr.right;
}
return list;
}
}
注意:
stack.pop()彈出的物件也是curr,就是當前指標指向的物件。我剛開始寫的時候新定義了一個TreeNode。
後序非遞迴寫法
後序非遞迴寫法,於先序遍歷相似,先序遍歷是從頂到底,先左後右,後序遍歷是從底到頂,先左後右。
所以需要反轉,為了便於比較,我把程式碼放在先序遍歷中。