数据结构 - 前中后序遍历

本文详细介绍了莫里斯遍历算法,一种不使用额外空间的遍历二叉树的方法,并展示了如何将其应用于前序、中序和后序遍历。同时,文中还提供了基于递归和栈的传统遍历方法作为对比。
摘要由CSDN通过智能技术生成

在介绍具体代码之前,先简述一下 莫里斯遍历 相关内容。

莫里斯遍历:不使用任何辅助空间

来到当前节点,记为cur

  • 如果cur无左孩子,cur向右移动, cur = cur.right

  • 如果cur有左孩子,找到cur左子树上最右的节点,记为mostRight

    • 如果mostRight的右子树为null, 让其指向cur,并将mostRight更新为cur, 原cur向左移动 cur = cur.left
    • 如果mostRight的右子树为cur, 让其右节点置为null, cur = cur.right

如果一个节点有左子树,可以到达两次,而且在第二次到达时,其左子树遍历完毕
若没有左子树,则只能到达一次

public void morrisIn(TreeNode root){
	if(root == null) return;
	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;
		}
		cur1 = cur1.right;
	}
}

前序遍历

方法一:递归

private List<Integer> ans = new ArrayList();
    public List<Integer> preorderTraversal(TreeNode root) {
        dfs(root);
        return ans; 
    }

    private void dfs(TreeNode root){
        if(root==null)
            return;
        ans.add(root.val);
        
        dfs(root.left);
        dfs(root.right);
    }

方式二:栈

public List<Integer> preorderTraversal(TreeNode root) {
        List<Integer> list = new ArrayList<>();
        if (root == null) {
            return list;
        }

        Stack<TreeNode> stack = new Stack<>();
        stack.push(root);
        while(!stack.isEmpty()) {
            TreeNode node = stack.pop();
            list.add(node.val);

            if (node.right != null) {
                stack.push(node.right);
            }

            if (node.left != null) {
                stack.push(node.left);
            }
        }
        return list;
 }

方法三、莫里斯遍历


```java
public List<Integer> preorderTraversal(TreeNode root) {
        List<Integer> ans = new ArrayList();
        if(root == null) return ans;

        TreeNode cur1 = root;
        TreeNode mostRight = null;
        
        while(cur1 != null){
            mostRight = cur1.left;
            if(mostRight != null){
                while(mostRight.right != null && mostRight.right != cur1) {
                    mostRight = mostRight.right;
                }

                if(mostRight.right == null){
                    mostRight.right = cur1;
                    ans.add(cur1.val);
                    cur1 = cur1.left;
                    continue;
                } else {
                    mostRight.right = null;
                }
            } else {
                ans.add(cur1.val);
            }
            cur1 = cur1.right;
        }
        return ans;
}

中序遍历

方法一:递归

public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> res = new ArrayList<Integer>();
        inorder(root, res);
        return res;
}

public void inorder(TreeNode root, List<Integer> res) {
        if (root == null) {
            return;
        }
        inorder(root.left, res);
        res.add(root.val);
        inorder(root.right, res);
}

方式二:栈

public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> ret = new ArrayList<>();
        if(root == null) return ret;

        Stack<TreeNode> stack = new Stack<>();
        TreeNode cur = root;
        while(cur!= null || !stack.isEmpty()){
            while(cur != null){
                stack.push(cur);
                cur = cur.left;
            }

            TreeNode node = stack.pop();
            ret.add(node.val);
            if(node.right != null){
                cur = node.right;
            }
        }
        return ret;
}

方法三、莫里斯遍历

public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> ret = new ArrayList<>();
        if(root == null) return ret;
        TreeNode cur1 = root, mostRight = null;
        
        while(cur1 != null){
            mostRight = cur1.left;
            if(mostRight != null){
                while(mostRight.right != null && mostRight.right != cur1) {
                    mostRight = mostRight.right;
                }
                if(mostRight.right == null){
                    mostRight.right = cur1;
                    cur1 = cur1.left;
                    continue;
                } else { 
                    mostRight.right = null;
                }
            }
            ret.add(cur1.val);
            cur1 = cur1.right;
        }
        return ret;
}

后序遍历

方法一:递归

 public List<Integer> postorderTraversal(TreeNode root) {
        List<Integer> ret = new ArrayList<Integer>();
        postorder(root, ret);
        return ret;
 }

public void postorder(TreeNode root, List<Integer> ret) {
        if (root == null) {
            return;
        }
        postorder(root.left, ret);
        postorder(root.right, ret);
        ret.add(root.val);
    }

方法二:栈

public List<Integer> postorderTraversal(TreeNode root) {
        if (root == null) {
            return new ArrayList<>();
        }

        List<Integer> ret = new ArrayList<>();
        Stack<TreeNode> stack = new Stack<>();
        TreeNode cur = root;
        TreeNode lastNode = null;

        while(!stack.isEmpty() || cur != null) {
            while(cur != null) {
                stack.push(cur);
                cur = cur.left;
            }

            TreeNode node = stack.peek();
            if (node.right != null && node.right != lastNode) {
                cur = node.right;
            } else {
                ret.add(node.val);
                stack.pop();
                lastNode = node;
            }
        }
        return ret;
 }

方法三:莫里斯遍历:在第二次到达时,然后逆序打印左子树的右边界,最后打印整棵树的右边界

List<Integer> ret = new ArrayList<>();
public List<Integer> postorderTraversal(TreeNode root) {
        if (root == null)  return ret;
        
        TreeNode cur1 = root, 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;
                    postMorrisPrint(cur1.left);
                }
            }
            cur1 = cur1.right;
        }
        postMorrisPrint(root);
        return ret;
}

public void postMorrisPrint(TreeNode head) {
        TreeNode reverseList = postMorrisReverse(head);
        TreeNode cur = reverseList;
        while (cur != null) {
            ret.add(cur.val);
            cur = cur.right;
        }
        postMorrisReverse(reverseList);
}

public TreeNode postMorrisReverse(TreeNode head) {
        TreeNode cur = head;
        TreeNode pre = null;
        while (cur != null) {
            TreeNode next = cur.right;
            cur.right = pre;
            pre = cur;
            cur = next;
        }
        return pre;
}
  • 9
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值