樹的遍歷合輯

前序遍歷html

遍歷順序爲root-->left-->right。遞歸方法省略。node

方法一:post

分析:採用棧實現,每次將根節點壓入棧,而後彈出棧頂元素,並把右節點和左節點依次壓入棧。運行時間爲2ms。代碼以下:spa

public class Solution {
    public List<Integer> preorderTraversal(TreeNode root) {
        List<Integer> rst = new LinkedList<Integer>();
        Stack<TreeNode> stack = new Stack<TreeNode>();
        if (root == null) return rst;
        stack.push(root);
        while (!stack.empty()) {
            TreeNode node = stack.pop();
            rst.add(node.val);
            if (node.right != null) {
                stack.push(node.right);
            }
            if (node.left != null) {
                stack.push(node.left);
            }
        }
        return rst;
    }
}

方法二:code

分析:一樣採用棧實現,但對於每一個節點只將其右節點壓入棧。運行時間爲1ms。htm

public class Solution {
    public List<Integer> preorderTraversal(TreeNode root) {
        List<Integer> rst = new LinkedList<Integer>();
        Stack<TreeNode> stack = new Stack<TreeNode>();
        TreeNode node = root;
        while (node != null || !stack.empty()) {
            rst.add(node.val);
            if (node.right != null) {
                stack.push(node.right);
            }
            node = node.left;
            if (node == null && !stack.empty()) {
                node = stack.pop();
            }
        }
        return rst;
    }
}

方法三:blog

分析:採用堆棧的空間複雜度爲O(n),而採用Morris Traversal空間複雜度爲O(1)。運行時間爲1ms。遞歸

public class Solution {
    public List<Integer> preorderTraversal(TreeNode root) {
        List<Integer> rst = new LinkedList<Integer>();
        TreeNode cur = root;
        while (cur != null) {
            if (cur.left == null) {
                rst.add(cur.val);
                cur = cur.right;
            } else {
                TreeNode prev = cur.left;
                while (prev.right != null && prev.right != cur) {
                    prev = prev.right;
                }
                if (prev.right == null) {
                    rst.add(cur.val);
                    prev.right = cur;
                    cur = cur.left;
                } else {
                    prev.right = null;
                    cur = cur.right;
                }
            }
        }
        return rst;
    }
}

 

中序遍歷leetcode

遍歷順序爲left-->root-->right。遞歸方法省略。get

方法一:

分析:採用棧實現,運行時間爲2ms。

public class Solution {
    public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> list = new ArrayList<>();
        Stack<TreeNode> stack = new Stack<>();
        TreeNode cur = root;
        while(cur != null || !stack.empty()){
            while(cur != null){
                stack.add(cur);
                cur = cur.left;
            }
            cur = stack.pop();
            list.add(cur.val);
            cur = cur.right;
        }
        return list;
    }
}

方法二:

分析:採用Morris Traversal方法,空間複雜度爲O(1),時間複雜度爲O(n)。運行時間爲1ms。與前序遍歷的Morris Traversal方法相同,只是將節點的值加入列表的位置不一樣。

public class Solution {
    public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> list = new ArrayList<Integer>();
        TreeNode cur = root;
        while(cur != null){
            if (cur.left == null) {
                list.add(cur.val);
                cur = cur.right;
            } else {
                TreeNode prev = cur.left;
                while (prev.right != null && prev.right != cur) {
                    prev = prev.right;
                }
                if (prev.right == null) {
                    prev.right = cur;
                    cur = cur.left;
                } else {
                    list.add(cur.val);
                    prev.right = null;
                    cur = cur.right;
                }
            }
        }
        return list;
    }
}

 

後序遍歷

遍歷順序爲left-->right-->root。遞歸方法省略。

方法一:

分析:後序遍歷至關於root-->right-->left的逆序遍歷,所以能夠向採用前序遍歷的方法一按root-->right-->left順序遍歷,而後將結果reverse便可。reverse結果與在迭代過程當中把每一個元素添加在list首部等效。運行時間爲2ms。

public class Solution {
    public List<Integer> postorderTraversal(TreeNode root) {
        List<Integer> rst = new LinkedList<Integer>();
        if (root == null) return rst;
        Stack<TreeNode> stack = new Stack<>();
        stack.push(root);
        while (! stack.empty()) {
            TreeNode temp = stack.pop();
            rst.add(0, temp.val);
            if (temp.left != null) stack.push(temp.left);
            if (temp.right != null) stack.push(temp.right);
        }
        return rst;
    }
}

方法二:

對應於前序遍歷的方法二,即只將左節點放入棧中。有兩種寫法。

I:運行時間2ms。

public class Solution {
    public List<Integer> postorderTraversal(TreeNode root) {
        List<Integer> rst = new LinkedList<Integer>();
        if (root == null) return rst;
        Stack<TreeNode> stack = new Stack<>();
        while (root != null || !stack.empty()) {
            if (root != null) {
                rst.add(0, root.val);
                stack.push(root.left);
                root = root.right;
            } else {
                root = stack.pop();
            }
        }
        return rst;
    }
}

II:運行時間爲1ms。

public class Solution {
    public List<Integer> postorderTraversal(TreeNode root) {
        List<Integer> rst = new LinkedList<Integer>();
        if (root == null) return rst;
        Stack<TreeNode> stack = new Stack<>();
        while (root != null || !stack.empty()) {
            rst.add(0, root.val);
            if (root.left != null) {
                stack.push(root.left);
            }
            root = root.right;
            if (root == null && !stack.empty()) {
                root = stack.pop();
            }
        }
        return rst;
    }
}

分析II比I快的緣由是II在將元素壓入棧時進行了判斷,只將非空元素壓入,所以壓入和彈出的次數會比I更小。而棧的壓入和彈出時間對本問題運行時間影響較大,所以II明顯比I快。

方法三:

分析:採用Morris Traversal方法。對應於前序遍歷方法三,只是將left和right互換。運行時間爲1ms。

public class Solution {
    public List<Integer> postorderTraversal(TreeNode root) {
        List<Integer> rst = new LinkedList<Integer>();
        TreeNode cur = root;
        while (cur != null) {
            if (cur.right == null) {
                rst.add(0, cur.val);
                cur = cur.left;
            } else {
                TreeNode prev = cur.right;
                while (prev.left != null && prev.left != cur) {
                    prev = prev.left;
                }
                if (prev.left == null) {
                    rst.add(0, cur.val);
                    prev.left = cur;
                    cur = cur.right;
                } else {
                    prev.left = null;
                    cur = cur.left;
                }
            }
        }
        return rst;
    }
}

在leetcode discuss中一些人提到根據前序遍歷方法將節點值每次加入到結果列表的首部並非嚴格意義上的後序遍歷。對於一些在過程當中就須要後序遍歷的狀況下這種方法並不適用。所以,考慮到代碼的通用性,須要實現真正意義上的後序遍歷。

方法四:

分析:使用一個節點記錄上一個被訪問的元素。對於每一個節點,將其左節點所有壓入棧。而後對於棧頂節點(棧頂節點的左子樹都已經被訪問過),判斷其右節點是否爲空或爲上個被訪問的元素,如果,則將棧頂節點彈出,不然對棧頂節點右節點進行一樣的操做(將其左節點所有壓入棧...)此方法運行時間爲2ms。

public class Solution {
    public List<Integer> postorderTraversal(TreeNode root) {
        List<Integer> rst = new LinkedList<Integer>();
        Stack<TreeNode> stack = new Stack<>();
        TreeNode cur = root;
        TreeNode prev = null;
        while (cur != null || !stack.empty()) {
            while (cur != null) {
                stack.push(cur);
                cur = cur.left;
            }
            cur = stack.peek();
            if (cur.right == null || cur.right == prev) {
                rst.add(cur.val);
                prev = cur;
                stack.pop();
                cur = null;
            } else {
                cur = cur.right;
            }
        }
        return rst;
    }
}

 

 

層序遍歷

方法一:

分析:BFS(4ms),採用queue實現,每次queue內保存當前層的全部節點。

public class Solution {
    public List<List<Integer>> levelOrder(TreeNode root) {
        List<List<Integer>> rst = new LinkedList<>();
        if (root == null) return rst;
        Queue<TreeNode> q = new LinkedList<>();
        q.offer(root);
        while (q.peek() != null) {
            int size = q.size();
            List<Integer> tmp = new LinkedList<>();
            while (size-- > 0) {
                TreeNode temp = q.poll();
                tmp.add(temp.val);
                if (temp.left != null) q.offer(temp.left);
                if (temp.right != null) q.offer(temp.right);
            }
            rst.add(new LinkedList<Integer>(tmp));
        }
        return rst;
    }
}

方法二:

分析:DFS(2ms),採用遞歸方法實現,每次將節點放入其對應層次的list中。

public class Solution {
    public List<List<Integer>> levelOrder(TreeNode root) {
        List<List<Integer>> rst = new LinkedList<>();
        if (root == null) return rst;
        dfs(root, rst, 0);
        return rst;
    }
    public void dfs(TreeNode node, List<List<Integer>> rst, int level) {
        if (rst.size() == level) {
            rst.add(new LinkedList<>());
        }
        rst.get(level).add(node.val);
        if (node.left != null) dfs(node.left, rst, level + 1);
        if (node.right != null) dfs(node.right, rst, level + 1);
    }
}

 

附註:Morris Traversal附加參考連接http://www.cnblogs.com/AnnieKim/archive/2013/06/15/MorrisTraversal.html

相關文章
相關標籤/搜索