1、二叉树遍历

1、 采用传统的递归  (O(n)的空间复杂度)   

  public void preOrder(TreeNode root) {
        if(root == null) 
            return;
        System.out.println(root.val);
        preOrder(root.left);
        preOrder(root.right);
    }
    
    public void inOrder(TreeNode root) {
        if(root == null) 
            return;
        preOrder(root.left);
        System.out.println(root.val);
        preOrder(root.right);
    }
    
    public void postOrder(TreeNode root) {
        if(root == null) 
            return;
        preOrder(root.left);
        preOrder(root.right);
        System.out.println(root.val);
    }

 

2、采用 Stack + 迭代的方式  (O(n)的空间复杂度)

  ①、先序遍历

    public void preOrder2(TreeNode root) {
        
        if(root == null)
            return;
        Stack<TreeNode> stack = new Stack<>();
        stack.add(root);
        
        while(!stack.isEmpty()) {
            
            TreeNode node = stack.pop();
            System.out.println(node.val);
            
            if(node.right != null)
                stack.add(node.right);
            if(node.left != null)
                stack.add(node.left);
        }
    }
    

   

  优化: Stack 只用于存储 Right 节点。

public List<Integer> preorderTraversal(TreeNode root) {
        List<Integer> result = new ArrayList<>();
        if(root == null)
            return result;
        // 只存储右节点
        Stack<TreeNode> rightStack = new Stack<>();
        TreeNode node = root;
        
        while(node != null) {
            result.add(node.val);
            if(node.right != null)
                rightStack.add(node.right);
            
            node = node.left;
            if(node == null && !rightStack.isEmpty())
                node = rightStack.pop();
        }
        return result;
    }

 

  ②、中序遍历

public void inOrder2(TreeNode root) {
        
        if(root == null)
            return;
        Stack<TreeNode> stack = new Stack<>();
        stack.add(root);
        
        while(!stack.isEmpty()) {
            TreeNode node = stack.peek();
            if(node.left != null) {
                stack.push(node.left);
                // 左节点以入栈,则标记为空,否则死循环
                node.left = null;
            }
            else {
                System.out.println(stack.pop().val);
                if(node.right != null)// 插入右节点
                    stack.push(node.right);
            }
        }
    }

  优化

  public void inOrder3(TreeNode root) {
        
        Stack<TreeNode> stack = new Stack<>();
        TreeNode cur = root;
        
        while(cur != null || !stack.isEmpty()) {
            
            while(cur != null) {
                // 将 cur 的左斜子树全部添加
                stack.add(cur);
                cur = cur.left;
            }
            
            cur = stack.pop();
            System.out.println(cur.val);
            cur = cur.right;
        }
    }

 

  ③、后续遍历

    a、采用 Stack 进行压栈操作,同时采用一个 Map 记录该节点的右孩子是否被访问过

public void postOrder2(TreeNode root) {
        
        // 用于标记结点的右孩子已经被遍历过
        Map<Integer, Integer> map = new HashMap<Integer, Integer>();
        Stack<TreeNode> stack = new Stack<>();
        TreeNode node;
        
        while(root != null || !stack.isEmpty()) {
            while(root != null) {
                stack.push(root);
                map.put(root.val, 0);    // 标记未访问
                root = root.left;
            }
            
            if(!stack.empty()) {
                node = stack.peek();
                
                // 此时左孩子为空, 若右孩子不为空且未被访问过,则访问右孩子
                if(node.right != null && map.get(node.val) != 1) {
                    root = node.right;
                    map.put(node.val, 1); //表示 node 结点的右孩子已经被遍历过
                }
                else {    //  若右孩子为空,则访问此节点.
                    stack.pop();
                    System.out.println(node.val);
                }
            }
        }
    }

 

 b、采用一个指针记录当前右孩子是否访问过

public void postOrder3(TreeNode root) {
        
        Stack<TreeNode> stack = new Stack<>();
        TreeNode pre = null;    // 记录前一个访问的节点,用于判断右孩子是否访问过
        TreeNode node;
        
        while(root != null || !stack.isEmpty()) {
            
            while(root != null) {
                stack.push(root);
                root = root.left;
            }
            
            if(!stack.isEmpty()) {
                
                node = stack.peek();
                if(node.right != null && node.right != pre) 
                    root = node.right;
                else {
                    System.out.println(node.val);
                    pre = node;
                    stack.pop();
                }
            }
        }
    }

  

  c、前序遍历比较好写,利用伪前序遍历方法的逆序来写后续遍历

    伪前序:根-->右-->左

    后续:左-->右-->根

    public void postOrder4(TreeNode root) {
        
        if(root == null)
            return;
        // 用于记录 根-->右-->左 的节点顺序
        List<TreeNode> list = new ArrayList<TreeNode>();
        Stack<TreeNode> stack = new Stack<>();
        stack.add(root);
        TreeNode node;
        while(!stack.isEmpty()) {
            
            node = stack.pop();
            list.add(node);
            
            if(node.left != null)
                stack.add(node.left);
            
            if(node.right != null)
                stack.add(node.right);
        }
        Collections.reverse(list);
        for(TreeNode tmp: list)
            System.out.println(tmp.val );
    }
    

 

3、Morris Traversal 方法线索二叉树,只需要O(1)空间,而且同样可以在O(n)时间内完成。

   引自: https://www.cnblogs.com/AnnieKim/archive/2013/06/15/MorrisTraversal.html

  主要思想是:

    根据中序遍历序列将叶子节点添加右索引,指向祖先节点。线索查找时根据条件输出即可。

 

  前序遍历

    void preOrderMorrisTraversa(TreeNode root) {
        
        TreeNode cur = root;
        TreeNode pre = null;
        
        
        while(cur != null) {
            if(cur.left == null) {
                System.out.println(cur.val);
                cur = cur.right;
            }
            else {
                pre = cur.left;
                while(pre.right != null && pre.right != cur)
                    pre = pre.right;
                if(pre.right == null) {    // 添加右线索
                    System.out.println(cur.val);
                    pre.right = cur;
                    cur = cur.left;
                }
                else {
                    pre.right = null;
                    cur = cur.right;
                }
            }
        }
    }

 

  中序遍历

    void inorderMorrisTraversal(TreeNode root) {
        
        TreeNode cur = root;
        TreeNode pre = null;
        
        while(cur != null) {
            
            if(cur.left == null) {
                System.out.println(cur.val + "-->");
                cur = cur.right;
            }
            else {
                pre = cur.left;
                while(pre.right != null && pre.right != cur)
                    pre = pre.right;
                
                if(pre.right == null) {
                    pre.right = cur;
                    cur = cur.left;
                }
                else {        // pre.right == cur , 此时断开线索
                    pre.right = null;
                    System.out.println(cur.val + "--->");
                    cur = cur.right;
                }
            }
        }
    }
    

 

  后序遍历

    void postorderMorrisTraversal(TreeNode root) {
        
        TreeNode dump = new TreeNode(0);
        dump.left = root;
        
        TreeNode cur = dump;
        TreeNode pre = null;
        
        while(cur != null) {
            
            if(cur.left == null) {
                cur = cur.right;
            }
            else {
                pre = cur.left;
                while(pre.right != null && pre.right != cur) 
                    pre = pre.right;
                
                if(pre.right == null) {
                    pre.right = cur;
                    cur = cur.left;
                }
                else {
                    // 将线索的一条右斜支链逆序输出
                    printReverse(cur.left, pre);
                    pre.right = null;
                    cur = cur.right;
                }
                    
            }
                
        }
    }

    private void printReverse(TreeNode from, TreeNode to) {
        reverse(from, to);
        
        TreeNode p = to;
        while(true) {
            System.out.println(p.val + " ");
            if(p == from)
                break;
            p = p.right;
        }
        reverse(to, from);
    }
    
    private void reverse(TreeNode from, TreeNode to) {
        
        if(from == to)
            return;
          
        TreeNode x = from;
        TreeNode y = from.right;
        
        while(true) {
            TreeNode z = y.right;
            y.right = x;
            x = y;
            y = z;
            if(x == to)
                break;
        }
    }

 

posted @ 2018-10-05 12:27  skillking2  阅读(303)  评论(0编辑  收藏  举报