左神算法笔记——Morris遍历

2020-04-11  本文已影响0人  yaco

基本问题——实现二叉树的前序、中序、后序遍历

(递归、非递归,mirros方法)

递归

  1. 递归方式下的前中后遍历
    // 前序遍历
    public List<Integer> preorderTraversal(TreeNode root) {
        // write your code here
        List<Integer> ans = new ArrayList<>();
        if(root != null){
            ans.add(root.val);
            if(root.left != null){
                ans.addAll(inorderTraversal(root.left));
            }
            if(root.right != null){
                ans.addAll(inorderTraversal(root.right));
            }
        }
        return ans;
    }

    // 中序遍历
    public List<Integer> inorderTraversal(TreeNode root) {
        // write your code here
        List<Integer> ans = new ArrayList<>();
        if(root != null){
            if(root.left != null){
                ans.addAll(inorderTraversal(root.left));
            }
            ans.add(root.val);
            if(root.right != null){
                ans.addAll(inorderTraversal(root.right));
            }
        }
        return ans;
    }
    
    // 后序遍历
    public List<Integer> postorderTraversal(TreeNode root) {
        // write your code here
        List<Integer> ans = new ArrayList<>();
        if(root != null) {
            if(root.left != null){
                ans.addAll(postorderTraversal(root.left));
            }
            if(root.right != null){
                ans.addAll(postorderTraversal(root.right));
            }
            ans.add(root.val);
        }
        return ans;
    }
}

非递归

  1. 非递归的方式实现三种遍历
    // 前序遍历
    public List<Integer> preorderTraversal(TreeNode root) {
        // write your code here
        List<Integer> ans = new ArrayList<>();
        if(root != null){
            Stack<TreeNode> stack = new Stack<>();
            stack.push(root);
            while(!stack.isEmpty()){
                root = stack.pop();
                ans.add(root.val);
                if(root.right != null){
                    stack.push(root.right);
                }
                if(root.left != null){
                    stack.push(root.left);
                }
            }
        }
        return ans;
    }

    // 中序遍历
    public List<Integer> inorderTraversal(TreeNode root) {
        // write your code here
        List<Integer> ans = new ArrayList<>();
        if(root != null){
            Stack<TreeNode> stack = new Stack<>();
            while(!stack.isEmpty() || root != null){
                if(root != null){
                    stack.push(root);
                    root = root.left;
                }else{
                    root = stack.pop();
                    ans.add(root.val);
                    root = root.right;
                }
            }
        }
        return ans;
    }

    // 后序遍历
    public List<Integer> postorderTraversal(TreeNode root) {
        // write your code here
        List<Integer> ans = new ArrayList<>();
        if(root != null) {
            Stack<TreeNode> stack = new Stack<>();
            Stack<Integer> data = new Stack<>();
            stack.push(root);
            while(!stack.isEmpty()){
                root = stack.pop();
                data.push(root.val);
                if(root.left != null){
                    stack.push(root.left);
                }
                if(root.right != null){
                    stack.push(root.right);
                }
            }
            // 将data数据返回
            while(!data.isEmpty()){
                ans.add(data.pop());
            }
        }
        return ans;
    }

Morris遍历

Morris遍历要点:

一张图理解Morris遍历路线


Morris遍历

通用的Morris遍历路线入上图所示:
首先不停的向左子树搜索,连接出所有的路径,等到了最左边的子节点,开始不停的向右走,一边走一边关闭之前开辟的路径。

    // 基础莫里斯遍历(没有添加遍历元素的添加)
    public List<Integer> Morris(TreeNode root){
        List<Integer> ans = new ArrayList<>();
        if(root != null) {
            TreeNode cur1 = root;   // 记录当前遍历的节点
            TreeNode cur2 = null;   // 记录当前节点的左子节点
            while(cur1 != null){
                cur2 = cur1.left;
                if(cur2 != null){
                    // 一直向右搜索,直到空或者回到了原始位置结束
                    while(cur2.right != null && cur2.right != cur1){
                        cur2 = cur2.right;
                    }
                    // 如果沿着cur2一直找到了空,表示为第一次遍历,那么连接到开始遍历的地方,且cur2继续向左走,去连接下面的节点
                    if(cur2.right == null){
                        cur2.right = cur1;   // cur1和cur2连接
                        cur1 = cur1.left;
                        continue;
                    }else{
                        cur2.right = null;
                    }
                }
                cur1 = cur1.right;
            }
        }
        return ans;
    }

在基础的Morris代码块之上,按照遍历要求填入不同的操作, 前序,中序,后序分别如下:

    // Morris前序遍历
    public List<Integer> preorderTraversal(TreeNode root) {
        // write your code here
        List<Integer> ans = new ArrayList<>();
        if(root != null){
            TreeNode cur1 = root;
            TreeNode cur2 = null;
            while(cur1 != null){
                cur2 = cur1.left;
                if(cur2 != null){
                    while(cur2.right != null && cur2.right != cur1){
                        cur2 = cur2.right;
                    }
                    if(cur2.right == null){
                        cur2.right = cur1;
                        ans.add(cur1.val);
                        cur1 = cur1.left;
                        continue;
                    }else{
                        cur2.right = null;
                    }
                }else{
                    ans.add(cur1.val);
                }
                cur1 = cur1.right;   // 入座left为null,或者cur2断开连接了,一直向右走
            }
        }
        return ans;
    }

中序遍历:

    // Morris中序遍历
    public List<Integer> inorderTraversal(TreeNode root) {
        // write your code here
        List<Integer> ans = new ArrayList<>();
        if(root != null){
            TreeNode cur1 = root;
            TreeNode cur2 = null;
            while(cur1 != null){
                cur2 = cur1.left;
                if(cur2 != null){
                    while(cur2.right != null && cur2.right != cur1){
                        cur2 = cur2.right;
                    }
                    if(cur2.right == null){
                        cur2.right = cur1;
                        cur1 = cur1.left;
                        continue;
                    }else{
                        cur2.right = null;
                    }
                }
                ans.add(cur1.val);
                cur1 = cur1.right;   // 入座left为null,或者cur2断开连接了,一直向右走
            }
        }
        return ans;
    }

后序遍历:

    // Morris后序遍历
    public List<Integer> postorderTraversal(TreeNode root) {
        // write your code here
        List<Integer> ans = new ArrayList<>();
        if(root != null){
            TreeNode cur1 = root;
            TreeNode cur2 = null;
            while(cur1 != null){
                cur2 = cur1.left;
                if(cur2 != null){
                    while(cur2.right != null && cur2.right != cur1){
                        cur2 = cur2.right;
                    }
                    if(cur2.right == null){
                        cur2.right = cur1;
                        cur1 = cur1.left;
                        continue;
                    }else{
                        cur2.right = null;
                        helper(ans,cur1.left);
                    }
                }
                cur1 = cur1.right;   // 入座left为null,或者cur2断开连接了,一直向右走
            }
            helper(ans,root);
        }
        return ans;
    }
    
    // 逆序添加节点到ans
    private void helper(List<Integer> ans, TreeNode root){
        TreeNode cur = reverseTree(root);
        TreeNode temp = cur;
        while(temp != null){
            ans.add(temp.val);
            temp = temp.right;
        }
        reverseTree(cur);
    }
    
    // 写一个反转链表的方法
    private TreeNode  reverseTree(TreeNode root){
        TreeNode pre = null;
        TreeNode next = null;
        while(root != null){
            next = root.right;
            root.right = pre;
            pre = root;
            root = next;
        }
        return pre;
    }

上一篇 下一篇

猜你喜欢

热点阅读