zoukankan      html  css  js  c++  java
  • 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;
            }
        }
  • 相关阅读:
    printf()函数不能直接输出string类型
    HDU 6166.Senior Pan()-最短路(Dijkstra添加超源点、超汇点)+二进制划分集合 (2017 Multi-University Training Contest
    计蒜客 17119.Trig Function-切比雪夫多项式+乘法逆元 (2017 ACM-ICPC 亚洲区(西安赛区)网络赛 F)
    POJ 1195.Mobile phones-二维树状数组
    HDU 1541.Stars-一维树状数组(详解)
    ACM中常见错误对应表
    HDU 6112.今夕何夕-蔡勒公式 (2017"百度之星"程序设计大赛
    hdu 2126 Buy the souvenirs 二维01背包方案总数
    codevs 1017 乘积最大 dp
    bzoj 2705: [SDOI2012]Longge的问题 欧拉函数
  • 原文地址:https://www.cnblogs.com/skillking/p/9744590.html
Copyright © 2011-2022 走看看