码迷,mamicode.com
首页 > 其他好文 > 详细

Binary Tree Xorder Traversal

时间:2018-03-19 19:03:21      阅读:170      评论:0      收藏:0      [点我收藏+]

标签:推荐   如何   迭代   img   tree   结束   logs   ack   rsa   

技术分享图片?


 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }

解题思路

1.语法:

与二叉树相关的问题, 不要想得太复杂,数据结构抽象如下 根节点 /
左子树 右子树 而左子树和右子树又可以看成和上面相同的数据结构, 即树具有递归性质的数据结构, 解决树的问题时,递归首选。

2.非递归解题思路:

二叉树除了根节点,所有的叶子节点都可以看成左节点或者右节点 关于子树根节点的处理很微妙,因为子树的根节点同样是上级子树的左儿子或者右儿子, 所以不用单独处理,只需要处理左右儿子节点就能搞定一棵树。如果根节点需要单独处理,只有一个也很容易处理。

先序遍历

先序遍历: 根-左-右, p.val 处理要在 p.left 和 p.right 处理之前

前序遍历中, 每个节点都是在它的子树之前处理. 然而, 尽管每个节点在其子树之前进行了处理, 但在向下移动的过程中还是需要保留一些信息. 当左子树遍历完成之后, 必须返回其右子树来继续遍历. 为了能够在左子树遍历完成后能移动到右子树, 必须保留根节点信息. 能够实现该信息存储的显然是栈, 它能以逆序获取信息并返回到右子树.

迭代解法

解法1

不推荐下面的解法, 以后都要使用解法二的思想.

class Solution {
    public List<Integer> preorderTraversal(TreeNode root) {
        TreeNode p = root;
        List<Integer> ans = new LinkedList<>();
        
        if (p == null) return ans;
        Stack<TreeNode> stack = new Stack<>();
        
        // 由于在下面区分树的左右儿子节点的方式处理所有节点, 所以根节点我们额外处理, 很麻烦
        stack.push(p);
        ans.add(p.val);
        
        // 这种写法, 是区分树的左右儿子节点的方式处理. 
        // 如果能以对待根节点的方式对待所有节点, 很简洁, 见解法2
        while (!stack.isEmpty()) {        
            // 所操作的 p 已入栈
            if (p.left != null) {
                p = p.left;
                ans.add(p.val);
                stack.push(p);
            } else {
                // 这样写真的很啰嗦, 因为我们使用 stack.peek 和 p 存储了当前需要处理节点的信息
                // 我们只要能获取当前节点的信息就好, 何必要双重, 很麻烦
                stack.pop(); // 当前节点入栈就处理了, 出栈, 然后处理它的右节点 
                p = p.right;
                if (p != null) { // 由于区分树的左右儿子节点的方式处理, 这里还需要对右节点进行处理 
                    ans.add(p.val);  
                    stack.push(p);
                } else {
                    //由于是先序遍历, 最后处理右孩子, 根节点和左孩子处理过了, 
                    // 我们不知道现在栈中是否还有元素, 所以要判断栈是否为空
                    if (!stack.isEmpty()) { 
                        p = stack.peek();
                        p.left = null; // 关键一步
                    }  
                }   
            }       
        }
        return ans;
    }
}

解法2

class Solution {
    public List<Integer> preorderTraversal(TreeNode root) {
        TreeNode p = root;
        List<Integer> ans = new LinkedList<>();
        Stack<TreeNode> stack = new Stack<>();
        
        // p != null 有双重效果:
        // 第一, 第一次循环栈为空, 我们不需要现将 p 压栈
        // 第二, 由于是先序遍历, 最后处理右孩子, 根节点和左孩子处理过了, 
        //       所以在处理右节点时, 栈可能是空的
        while (!stack.isEmpty() || p != null) {
            if (p != null) {
                ans.add(p.val);
                stack.push(p);
                p = p.left;
            } else {
                // 这里不用判断栈是否为空是由于, 循环条件二选一, p == null, 则栈就不为空
                p = stack.pop().right;   
            }
        }
        return ans;
        
    }
}

递归解法

class Solution {
    public List<Integer> preorderTraversal(TreeNode root) {
        List<Integer> ans = new LinkedList<>();
        helper(root, ans);
        return ans;
    }
    public void helper(TreeNode root, List<Integer> ans) {
        // 函数返回值为 void, return 就好, 使用  return null 是错误的
        if (root == null) return; 
        ans.add(root.val);
        helper(root.left, ans);
        helper(root.right, ans);   
    }
}

中序遍历

中序遍历: 左-根-右, p.val 处理要在 p.left 和 p.right 处理之中

迭代解法

class Solution {
    public List<Integer> inorderTraversal(TreeNode root) {
        TreeNode p = root;
        List<Integer> ans = new LinkedList<>();
        Stack<TreeNode> stack = new Stack<>();
        
        while (!stack.isEmpty() || p != null) {
            if (p != null) {
                stack.push(p);
                p = p.left;
            } else {
                p = stack.pop();
                ans.add(p.val);
                p = p.right;
            }
        }
        return ans;
    }
}

递归解法

class Solution {
    public List<Integer> inorderTraversal(TreeNode root) {
        TreeNode p = root;
        List<Integer> ans = new LinkedList<>();
        helper(p, ans);
        return ans;
    }
    
    private void helper(TreeNode root, List<Integer> ans) {
        if (root == null) return;
        helper(root.left, ans);
        ans.add(root.val);
        helper(root.right, ans);
    }
}

后续遍历

后续遍历: (左-右-根), p.val 处理要在 p.left 和 p.right 处理之后

在后续遍历中, 每个节点需要访问2次, 这意味着, 遍历完左子树之后要访问当前节点, 遍历完右子树后还需要访问当前节点, 但是只有在第二次访问才会处理当前节点. 问题就是如何区分两次访问, 是遍历完左子树返回还是遍历完右子树返回?

解决方法: 当栈中出栈一个元素, 检查这个元素是否与栈顶元素右节点相同, 如果是, 则说明完成了左右子树遍历. 此时只需将栈顶元素出栈并输出该节点数据就好.

迭代解法

解法1

public List<Integer> postorderTraversal(TreeNode root) {

    LinkedList<Integer> result = new LinkedList<>();
    Deque<TreeNode> stack = new ArrayDeque<>();
    TreeNode p = root; // 很重要的一步
    
    // 使用循环代替递归, while 循环中要用到 栈是否为空的条件 
    while(!stack.isEmpty() || p != null) {  
        // 先处理根节点, 在处理右节点, 在处理左节点, 用的是栈的结构, 所以变成 左-右-根   
        if(p != null) {
            stack.push(p);
            result.addFirst(p.val);  // 其实就是栈
            p = p.right;          
        } else {
            TreeNode node = stack.pop();
            p = node.left;           
        }
    }
    return result;
}

解法2

class Solution {
    public List<Integer> postorderTraversal(TreeNode root) {
        
        TreeNode p = root;
        List<Integer> ans = new LinkedList<>();
        Stack<TreeNode> stack = new Stack<>();
        
        while (!stack.isEmpty() || p != null) {
            if (p != null) {
                stack.push(p);     
                p = p.left;
            } else {
                // 当前栈顶元素左子树处理完成, 下面处理右右子树
                // 如果左右节点皆为空, 处理根节点
                if (stack.peek().right == null) {
                    p = stack.pop(); 
                    ans.add(p.val);
                    
                    // 处理完根节点之后看看根节点的位置, 看它是在父节点的左节点还是右节点位置
                    // 如果是右节点的位置, 那么就一直回溯(由于左节点已经处理完, 右节点也处理完, 
                    // 只需处理根), 直到栈为空或者节点为父节点的左子树.
                    // 
                    while (!stack.isEmpty() && p == stack.peek().right) {
                        p = stack.pop();
                        ans.add(p.val);
                    }    
                }
                if (!stack.isEmpty()) { // 后续遍历, 栈为空, 则遍历结束
                    p = stack.peek().right;
                } else {
                    break;
                }        
            }   
        }
        return ans;    
    }
}

递归解法


class Solution {
    public List<Integer> postorderTraversal(TreeNode root) {
        List<Integer> ans = new LinkedList<>();
        helper(root, ans);
        return ans;
    }
    public void helper(TreeNode root, List<Integer> ans) {
        // 函数返回值为 void, return 就好, 使用  return null 是错误的
        if (root == null) return; 
        helper(root.left, ans);
        helper(root.right, ans);
        ans.add(root.val);
    }
}

层次遍历

class Solution {
    public List<List<Integer>> levelOrder(TreeNode root) {
        
        TreeNode p = root;
        List<List<Integer>> ans = new LinkedList<>();
        List<Integer> res = new LinkedList<>();
        if (p == null) return ans;
        
        Queue<TreeNode> queue = new LinkedList();
        queue.add(root);
        while (!queue.isEmpty()) {
            TreeNode temp = queue.remove();
            res.add(temp.val);
            if (temp.left != null) queue.add(temp.left);
            if (temp.right != null) queue.add(temp.right);
        }
        ans.add(res);
        
        
        
        return ans;     
    }
}

Binary Tree Xorder Traversal

标签:推荐   如何   迭代   img   tree   结束   logs   ack   rsa   

原文地址:https://www.cnblogs.com/nowgood/p/Binary-Tree-Xorder-Traversal.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!