二叉树的三种遍历方式(递归、非递归)

189 阅读2分钟

本文主要介绍二叉树遍历的三种方式:

  1. 前序遍历
  2. 中序遍历
  3. 后序遍历

同时分别用递归和非递归的方式实现,给出尽可能间接的代码模版,方便大家在面试的时候可以直接套用。

节点结构

首先定义二叉树每个节点的数据结构。

/**
 * 节点数据结构
 */
class TreeNode {
  val: number
  left: TreeNode | null
  right: TreeNode | null
  constructor(val?: number, left?: TreeNode | null, right?: TreeNode | null) {
    this.val = (val === undefined ? 0 : val)
    this.left = (left === undefined ? null : left)
    this.right = (right === undefined ? null : right)
  }
}

前序遍历

针对每个节点,我们首先访问当前节点,然后访问左节点,最后访问右节点。

递归

/**
 * 前序遍历递归实现
 * @param root 
 */
function preOrderTraversal(root: TreeNode | null) : number[] {
  if(root) {
    return [root.val, ...preOrderTraversal(root.left), ...preOrderTraversal(root.right)]
  }else {
    return []
  }
}

非递归

/**
 * 前序遍历的非递归过程
 * @param root 
 */
function preOrderTraversalIterate(root: TreeNode | null) : number[] {
  if(root === null) return []
  const stack: TreeNode[] = []
  const ret = []
  // stack.push(root)
  let node: TreeNode | null = root
  while(stack.length || node) {
    while(node) {
      ret.push(node.val)
      stack.push(node)
      node = node.left
    }
    node = stack.pop() as TreeNode
    node = node.right
  }
  return ret
}

中序遍历

针对每个节点,我们首先访问左节点,然后访问当前节点,最后访问右节点。

递归

/**
 * 中序遍历递归实现
 * @param root 
 */
function inOrderTraversal(root: TreeNode | null): number[] {
  if(root) {
    return [...inOrderTraversal(root.left), root.val, ...inOrderTraversal(root.right)]
  }else {
    return []
  }
}

非递归

/**
 * 中序递归迭代实现
 * @param root 
 */

function inOrderTraversalIterate(root: TreeNode | null): number[] {
  if(root === null) return []
  const ret = []
  const stack: TreeNode[] = []
  let node: TreeNode | null = root

  while(stack.length || node) {
    while(node) {
      stack.push(node)
      node = node.left
    }
    node = stack.pop() as TreeNode
    ret.push(node.val)
    node = node.right
  }
  return ret
}

后序遍历

针对每个节点,我们首先访问左节点,然后访问右节点,最后访当前节点。

递归

/**
 * 后续遍历递归实现
 * @param root 
 */
function postOrderTraversal(root: TreeNode | null) : number[] {
  if(root) {
    return [...postOrderTraversal(root.left), ...postOrderTraversal(root.right), root.val]
  }else {
    return []
  }
}

非递归


/**
 * 后序遍历的非递归实现
 * @param root 
 */
function postOrderTraversalIterate(root: TreeNode | null): number[] {
  if (root === null) return [];

  const ret: number[] = [];
  const stack: TreeNode[] = [];
  let prev: TreeNode | null = null;
  let node: TreeNode | null = root;
  while (node || stack.length) {
    while (node) {
      stack.push(node);
      root = node.left;
    }

    node = stack.pop() as TreeNode;

    // 检查右子树是否存在或者是否已经访问过
    if (!node.right || node.right === prev) {
      ret.push(node.val);
      prev = node;
      node = null; // 置空root,以便下一次弹出栈顶元素
    } else {
      // 将当前节点重新入栈,处理右子树
      stack.push(node);
      node = node.right;
    }
  }

  return ret;
}