非递归遍历二叉树

非递归前序遍历

在这里插入图片描述

public List<TreeNode> perOrderTraversal(TreeNode root) {
		// 判空 
        if (root == null) {
            return null;
        }
        TreeNode node = root;
        // 创建List保存返回结果
        List<TreeNode> list = new ArrayList<>();
        // 创建栈辅助遍历二叉树
        Stack<TreeNode> stack = new Stack<>();
        while (true) {
            if (node != null) {
            	// 因为是前序遍历, 因此从根节点直接开始加入List中
                list.add(node);
                // 如果当前遍历到的节点有右子树, 将右子树入栈.
                if (node.right != null) {
                    stack.push(node.right);
                }
                // 更改当前节点, 一直向左遍历, 直到遍历到上图节点H
                node = node.left;
            } else if (stack.isEmpty()) {
            	// 如果栈为空, 则证明遍历结束
                return list;
            } else {
            	// 走到这里说明node此时已经等于 节点H.left, 也就是说整棵二叉树左子树已经遍历完毕, 
            	// 此时栈中元素为[C, E, G, I]
            	// 因此我们让 node =  stack.pop() 即弹出栈顶元素I, 让右子树继续执行左子树执行过的操作
            	// 直到整棵二叉树遍历完毕, list中元素即为前序遍历结果.
                node = stack.pop();
            }
     }
}

非递归中序遍历

在这里插入图片描述

public List<TreeNode> inOrderTraversal(TreeNode root){
		// 判空
        if (root == null) {
            return null;
        }
        TreeNode node = root;
        // 创建List保存返回结果
        List<TreeNode> list = new ArrayList<>();
        // 创建栈辅助遍历二叉树
        Stack<TreeNode> stack = new Stack<>();
        while (true) {
            if (node != null) {
            	// 因为是中序遍历, 因此如果当前节点不为空, 便将其入栈
                stack.push(node);
                // 一直遍历左子树, 直到上图H节点
                node = node.left;
            } else if (stack.isEmpty()) {
            	// 如果栈为空, 则证明遍历结束
                return list;
            } else {
            	// 走到这里说明当前节点为null 且栈不为空, 即当前位于图中H.left. 
            	// 栈中元素为[A, B, D, F, H] 因此我们弹出栈顶元素H , 将其加入结果集list
            	// 然后将当前遍历节点指向H.right, 若H节点有右子树, 则会进行同左子树相同的遍历操作
            	// 因为图中H元素没有右子树, 即node = null, 因此继续弹出栈中元素, 直到栈为空, 遍历结束
                node = stack.pop();
                list.add(node);
                node = node.right;
            }
        }
    }

非递归后序遍历

在这里插入图片描述

public List<TreeNode> postOrderTraversal(TreeNode root){
		// 判空
        if (root == null) {
            return null;
        }
        TreeNode node;
        // 创建prev节点, 用于保存上一次遍历的节点, 若上一次遍历的节点为当前节点的子节点
        // 则需要遍历当前节点.
        TreeNode prev = null;
        // 创建List保存返回结果
        List<TreeNode> list = new ArrayList<>();
        // 创建栈辅助遍历二叉树
        Stack<TreeNode> stack = new Stack<>();
        // 将根节点入栈
        stack.push(root);
        // 若栈不为空则执行循环
        while (!stack.isEmpty()) {
         	// 将node赋值为栈顶元素(栈顶元素不弹出)
            node = stack.peek();
            // 若当前元素为叶子节点或上一个元素为当前元素子节点
            if (isLeaf(node) || isChild(node, prev)) {
            	// 将pop赋值为栈顶元素(弹出)
                node = stack.pop();
                // 更新prev
                prev = node;
                // 将当前遍历元素加入结果集
                list.add(node);
            // 当前元素还有左右子树, 将不为空的子树入栈(注意: 先入右子树, 后入左子树)
            } else {
                if (node.right != null) {
                    stack.push(node.right);
                }
                if (node.left != null) {
                    stack.push(node.left);
                }
            }
        }
        return list;
    }
	// 判断node是否为叶子节点
    public boolean isLeaf (TreeNode node) {
        return node.left == null && node.right == null;
    }

	// 判断node2是否为node1的子节点
    public boolean isChild (TreeNode node1, TreeNode node2) {
        if (node1 == null) {
            return false;
        }
        return node2 == node1.left || node2 == node1.right;
    }

以上面的后续遍历图为例:
①:将root入栈
栈中元素: [A]
②: 将root左右子树入栈
栈中元素: [A, C, B]
③: 将root更新为栈顶元素即 B, 将B左右子树入栈
栈中元素: [A, C, B, E, D]
④: 将B更新为栈顶元素即 D, 将D左右子树入栈
栈中元素: [A, C, B, E, D, G, F]
⑤: 将D更新为栈顶元素即 F, 将F左右子树入栈
栈中元素: [A, C, B, E, D, G, F, I, H]
⑥: 将F更新为栈顶元素即 H, 因为H为叶子节点, 因此将栈顶元素H弹出加入结果集, 将prev更新为H
栈中元素: [A, C, B, E, D, G, F, I]
⑦: 将H更新为栈顶元素即 I, 因为I为叶子节点, 因此将栈顶元素I弹出加入结果集, 将prev更新为I
栈中元素: [A, C, B, E, D, G, F]
⑧: 将I更新为栈顶元素即 F, 因为F不是叶子节点, 但是prev为I, 是F的子树, 因此将栈顶元素F弹出加入结果集, 将prev更新为F.
如果不添加子节点判断, 遍历到F时判断F不是叶子节点, 因此讲F的左右子树H, I加入栈中,就变成了死循环. 这就是添加prev保存前一个遍历元素的原因.

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值