深度优先遍历可以不用递归吗?

369 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第13天,点击查看活动详情

深度优先遍历可以不用递归吗?

我们在工作中遇到的一些数据问题,很多都是可以用递归来实现.
如果一个递归搞不定的话,就再来一个递归!
但是我们都知道递归是非常耗时的,一旦数据量庞大起来,递归次数多了,这个时间是非常恐怖的。
如何吧一些递归问题给非递归化,来达到某一定的效率。通常递归转化为非递归用到了栈和队列 深度优先遍历可以不用递归吗? 答案是肯定的:

  • 可以不用递归
  • 用栈,就可以实现
    • 因为递归本身就是栈
    • 递归在代码的底层也是用栈来实现的 用二叉树的先序遍历举例(先遍历当前节点,再遍历左节点,再遍历右节点):
  • 对于当前的节点来说
    1. 步骤一: 弹栈,拿到栈顶的节点
    2. 步骤二: 把右节点压栈
    3. 步骤三: 压入左节点 (这样弹栈的时候会先拿到左节点遍历,符合深度优先遍历要求)。
    4. 步骤四: 如果节点不为空,重复步骤 1, 如果为空,结束遍历。 整体思路还是比较清晰的,使用栈来将要遍历的节点压栈,然后出栈后检查此节点是否还有未遍历的节点,有的话压栈,没有的话不断回溯(出栈)。
      有了思路,不难写出如下用栈实现的二叉树的深度优先遍历代;

我们用144. 二叉树的前序遍历 (前序遍历是深度优先遍历的一种)进行举例:

var preorderTraversal = function (root) {
  if (root == null) { 
      return []; 
  }
  let stack = []
  let res = []
  stack.push(root)
  // 先遍历当前节点
  while (stack.length !== 0) {
    // 弹栈,拿到栈顶的节点,如果节点不为空,重复步骤 
    let treeNode = stack.pop()
    res.push(treeNode.val)
    // 先压右节点 
    if (treeNode.right != null) {
      stack.push(treeNode.right);
    }

    // 再压左节点 
    if (treeNode.left != null) {
      stack.push(treeNode.left);
    }
  }
  return res
};

执行结果

image.png

题外话

二叉树的 前序、后序、中序遍历都可以套这种模板进行遍历,一招鲜吃遍天!