1. 程式人生 > >LeetCode刷題Easy篇二叉樹遍歷

LeetCode刷題Easy篇二叉樹遍歷

題目

二叉樹的前序,中序,後序遍歷

Example Tree

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。

 

後序非遞迴寫法

後序非遞迴寫法,於先序遍歷相似,先序遍歷是從頂到底,先左後右,後序遍歷是從底到頂,先左後右。

所以需要反轉,為了便於比較,我把程式碼放在先序遍歷中。