你可能不知道的二叉树中序遍历(迭代方式实现)

151 阅读3分钟

前言:

力扣链接:145.二叉树的后序遍历

不同于前文中提到的前序、后序的迭代遍历方式,前序遍历的顺序是中左右,先访问的元素是中间节点。要处理的元素也是中间节点,由于前序遍历访问的节点与处理的节点为同一节点。而对于后序遍历实际上只是对前序遍历进行了一个数组的翻转,本质与前序遍历并无区别。

而对于中序遍历,中序遍历是左中右,先访问的是二叉树顶部的节点,然后一层一层向下访问,直到到达树左面的最底部,再开始处理节点,这就造成了处理顺序和访问顺序是不一致

基础介绍:

    • 二叉树的中序遍历是一种按照特定顺序访问二叉树节点的方法,其顺序为 “左 - 根 - 右”。这意味着在遍历二叉树时,首先会递归地遍历节点的左子树,然后访问当前节点,最后再递归地遍历节点的右子树。
    • 例如,对于下面这棵简单的二叉树:
     1
   /   \
  2     3
 / \   / \
4   5 6   7
  • 其中序遍历的顺序是 4、2、5、1、6、3、7。先从根节点 1 开始,它的左子树的根节点是 2,继续往左,最左边的节点是 4,所以先访问 4;然后访问 4 的父节点 2,接着访问 2 的右子树的节点 5;此时左子树遍历完成,访问根节点 1;再遍历根节点 1 的右子树,右子树的根节点是 3,其左子树最左边节点是 6,访问 6,接着访问 6 的父节点 3,最后访问 3 的右子树的节点 7。

首先定义两个数组,一个用于存储中序遍历的数组,另一个用于模仿栈

将根节点(root)赋给cur

使用while循环实现迭代

判断条件:

1.是栈不能为空

2.cur不能是null:这是因为当我们将根节点的左边全部进行遍历后会使得栈变为空的,

此时右边却还没有进行遍历,因此需要加上对cur是否为空值的判断,才能将右边进行全部的遍历。

var inorderTraversal = function (root) {
    let stack=[]
    let arr=[]
    let cur=root
    while(stack.length||cur){
        if(cur){
            stack.push(cur)
            cur=cur.left
        }
        else{
            cur=stack.pop()
            arr.push(cur.val)
            cur=cur.right
        }
    }
    return arr
};
  • 处理左子树节点并压入栈(if (cur) 分支)

    • 当 cur 不为 null 时,意味着当前节点存在,按照中序遍历 “左 - 根 - 右” 的顺序,首先要处理左子树,所以先将当前节点 cur 压入栈 stack 中,然后更新 cur 为其左子节点(cur = cur.left),这样在下一轮循环中,如果左子节点还存在,就会继续将其左子节点压入栈,不断深入左子树,直到遇到左子树的叶子节点(左子节点为 null)。
  • 弹出栈顶节点并处理(else 分支)

    • 当 cur 为 null 时,说明已经到达了当前节点左子树的最底层(左子节点都已经处理完或者本身就没有左子树),此时按照中序遍历顺序,应该访问根节点了,所以通过 cur = stack.pop() 从栈中弹出一个节点,这个节点就是当前子树的根节点(按照遍历顺序,之前已经把它的左子树节点都压入栈了,现在左子树处理完了,该它了)。
    • 接着将弹出节点的值 cur.val 存入结果数组 arr 中,这一步实现了对根节点值的记录,符合中序遍历 “左 - 根 - 右” 中访问根节点的要求。
    • 最后,将 cur 更新为其右子节点(cur = cur.right),准备去处理当前节点的右子树,开始下一轮循环,继续探索右子树的节点情况,重复上述过程,直到整个二叉树的所有节点都被访问并记录到 arr 数组中。