Leecode 二叉树的前、中、后序遍历解法

题目

给定一个二叉树,返回它的 前序 遍历。
给定一个二叉树,返回它的 中序 遍历。
给定一个二叉树,返回它的 后序 遍历。
但是很明显,如果是递归写法,十分简单,不会是中等难度了
题上也明确表示了,写 迭代算法

	public List<Integer> preorderTraversal(TreeNode root) {
	
	}

ps : 这三道题的题号分别是144,94,145

什么是二叉树

百度直达链接 二叉树

前序、中序、后序

  • 前序: 先输出根节点,然后输出左孩子节点,然后输出右孩子节点。对于树中的每一颗子树都一样
  • 中序: 先输入左孩子节点,然后输入根节点,再输出右孩子节点
  • 后续: 先输出左孩子节点,再输出右孩子节点,然后输出根节点
    其实所谓的某序,指的就是根节点的顺序。这样记的话就很容易记得了。

解题思路

首先需要一个数据结构来存取我们的树节点。而且需要的是存取比较方便的数据结构,那么就可以是队列或者栈。 可以根据实际情况选择。

前序遍历

根 - 左- 右的顺序。 先添加root节点到存储的数据结构中。
根节点加入到链表中,然后当链表不为空的时候,遍历栈或者队列,取出根节点,加入到结果链表中。往链表放入根节点的两个孩子节点中不为空的节点。 下一次循环:取出栈或者队列中的节点,此时必须取出“上一次取出节点”的左节点。 。
此时进行思考 :我们到底是选用栈还是队列?
不论栈还是队列,都需要进行判断

	while( ! stack or queue.isEmpty()) {
	}
1.假设选用队列,遍历完了根节点,然后选择加入根节点的左右孩子节点,应该先加左节点,后加右节点(因为队列的属性是FIFO,这样填充才能保证下一次首先取出来的是左孩子)。
看起来似乎没有问题,但是继续往下走,第二次进来的时候先取出左节点,然后就会往队列中加入它的左右孩子。然后下一次进入循环,并不是取出上一个节点的左右孩子,而是取出了它的兄弟节点(就是跟他同一层的另一个节点)。 这样就不符合前序遍历规则了。
2.假设选用栈,此时加入孩子节点的顺序就要换一下。  先加入根节点的右孩子节点,然后加入根节点的左孩子节点。
这样才可以保证每一次取出节点时取出来的是左孩子节点。
    public List<Integer> preorderTraversal(TreeNode root) {
        List<Integer> ans; = new ArrayList<>();
        Deque<TreeNode> stack = new ArrayDeque<>();
        //特殊判断
        if(root == null)
            return ans;
        //加入根节点
        stack.push(root);
        while (! stack.isEmpty()) {
            TreeNode cur = stack.pop();
            ans.add(cur.val);
            //先加入不为空的右孩子
            if(cur.right != null){
                stack.push(cur.right);
            }
            //加入不为空的左孩子
            if(cur.left != null)
                stack.push(cur.left);
        }
        return ans;
    }

中序遍历

时间关系,思路其实是一样的,建议画图,比较清晰明了
直接贴代码:

class Solution {

    public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> ans = new ArrayList<>();
        Deque<TreeNode> stack = new ArrayDeque<>();

        while (root != null || !stack.isEmpty()) {
            //一直添加左节点,循环结束时,root是左子节点
            while (root != null){
                //第一次进来 加入root节点到stack
                stack.push(root);
                root = root.left;
            }
            //左子节点赋给root。每次出来一个左节点。
            //就需要把他的右子树加入到结果中。因为他如果作为一个root节点,那么他的左子树肯定都进入stack了
            //根据中序遍历,规则,现在就需要把右子树加进来。
            root = stack.pop();
            ans.add(root.val);
            //将root置换为当前节点的右节点。 对当前节点的右子树进行中序遍历
            root = root.right;
        }

        return ans;
    }
}

后序遍历

class Solution {
    public List<Integer> postorderTraversal(TreeNode root){
       LinkedList<Integer> ans = new LinkedList<>();
       //特殊判断
       if(root == null)
            return ans;
        Deque<TreeNode> stack = new ArrayDeque<>();
        //加入根节点,既然根节点第一个出来,那顺序就是反的。可以采取头插法,这样最终的顺序就是正确的
        stack.push(root);
		
        while (!stack.isEmpty()) {
            TreeNode cur = stack.pop();
            //头插法;
            ans.addFirst(cur.val);
            //加入左孩子
            if(cur.left != null) {
                stack.push(cur.left);
            }
            //加入右孩子
            if(cur.right != null){
                stack.push(cur.right);
            }
        }
        return ans;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值