学点算法(十)——二叉树中序遍历算法(迭代实现)

今天我们继续来学习二叉树的中序遍历算法。

学点算法(九)——二叉树中序遍历算法(递归实现)中我们已经学习了二叉树中序遍历的递归算法,今天我们继续来学习它的迭代算法。

我们先来看整个遍历的过程,如图所示(重新播放需要刷新网页):
绿色表示该节点已遍历,序号表示遍历到的次序
我们可以发现对于每棵子树来说,遍历总是从子树的左下角开始,然后依次回溯到相对应的父节点,最后整体上回归到根节点,在回溯每个父节点的过程中,它又会去遍历一下它的右子树,遍历过程继续沿用该种遍历方法,最后直至所有的节点遍历完成。整体的遍历方向,如下所示:

在这里插入图片描述
但是我们起始位置是根节点,如何去找到最左下角的节点呢?我们只能通过不断地去查找节点的左孩子,然后查找左孩子的左孩子,一直找到它没有左孩子为止,那么最后的节点就是待遍历子树的左下角的节点了。我们可以加入一个指针来指示查找过程,指针的跳转也意味查找过程中节点的变化。
如下所示:
在这里插入图片描述
随后我们对该节点执行特定方法,比如说打印一下,即完成了这个节点的遍历。

遍历完这个左下角节点后,指针就回到了它的父节点,如下:
在这里插入图片描述
同时该节点也自成一棵左子树,那么根据定义,接下来我们就要遍历该子树的根节点,即该节点的父节点,这个很好理解,比如下面这三个节点:
在这里插入图片描述
2为这棵子树的根节点,也为其左子树的根节点1的父节点。

而这个多层的:
在这里插入图片描述
4为这棵子树的根节点,也为其左子树的根节点2的父节点。

遍历完根节点后,我们不能直接回溯到根节点的父节点,还需要遍历右子树,这时右子树只有一个节点,直接遍历它。
在这里插入图片描述
此时我们就进行了一轮完整的左子树-根节点-右子树的遍历,而我们要完成对整个树的遍历,就要对这个过程进行推广,如下所示:
在这里插入图片描述
这是更上一层的树。看到这个图,我想大家应该很快可以理解,接下来我们只需要回到原来的小子树的根节点,遍历它,然后再去遍历它的右子树即可,而每一层之间这样逐层传递遍历,最后直至到整棵树的根节点,然后再遍历整棵树的右子树即完成整棵树的遍历。

在这个逐层传递的过程中,我们需要依次回溯找到所有右子树的根节点,因为我们无法直接知道一棵树有几层,而这里根节点的特点是先遇到但是不遍历,一步步回溯的时候再遍历,所以我们可以借助栈来保存各个根节点,在每棵子树遍历完后依次取出即可。最后栈中没有元素的时候,也即表示遍历结束。

我们使用黄颜色来表示放入栈中的元素,那么整个过程指针的变化如下所示(右子树遍历过程与左子树雷同,不再展示)(重新播放需要刷新网页):
在这里插入图片描述
代码实现如下:

public static List<Integer> inorderTraversal(TreeNode root) {
    if (root == null) {
        // 根节点为null,返回空列表
        return Collections.emptyList();
    }
    List<Integer> elems = new ArrayList<>();
    Deque<TreeNode> stack = new ArrayDeque<>();
    // 控制权所在节点
    TreeNode currentNode = root;
    while (true) {
        while (currentNode != null) {
            // 当前节点入栈
            stack.push(currentNode);
            // 控制权交给左孩子
            currentNode = currentNode.left;
        }
        if (stack.isEmpty()) {
            // 栈为空,表示所有元素已经遍历结束,退出
            break;
        }
        // 弹出栈里面保存的节点,待进一步处理
        currentNode = stack.pop();
        // 弹出节点后,需要立即处理节点
        elems.add(currentNode.val);
        // 控制权交给右孩子,遍历节点的右子树
        currentNode = currentNode.right;
    }
    return elems;
}

我们可以沿用学点算法(九)——二叉树中序遍历算法(递归实现)的测试代码,改下方法名:

public static void main(String[] args) {
    System.out.println(inorderTraversal(TreeNode.convertArray2Tree(new Integer[]{31, 32, null, 34, 41, 42, 43})));
}

输出结果如下:

[42, 34, 43, 32, 41, 31]

符合我们的预期。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值