二叉树遍历(前序、中序、后序)

1,704 阅读2分钟

二叉树有多种遍历方法,本文对二叉树的先序、中序、后序的非递归遍历进行分析。代码编写为 javascript。

1 下面为二叉树的数据结构

let root = {
    val: 1,
    left: {
        val: 2,
        left: {
            val: 3
        },
        right: {
            val: 4
        }
    },
    right: {
        val: 5,
    }
}

截屏2021-07-30 下午2.52.50.png

  • 先序遍历结果(根左右):1 2 3 4 5 6
  • 中序遍历结果(左根右):3 2 1 5 4 6
  • 后序遍历结果(左右根):3 2 5 6 4 1

三种遍历方法区别如下

  • 先序:遍历到一个节点,即可输出该节点的值,并继续遍历左、右子树
  • 中序:遍历到一个节点,将其暂存,遍历完左子树后,再输出该节点的值,再遍历右子树
  • 后序:遍历到一个节点,将其暂存,遍历完左右子树后,在输出该节点的值

2 先序遍历

声明两个变量 stack、result,类型为数组;stack 用来存储遍历到的节点,result 用来存储当前节点的值。总体思路为确定 stack 入栈出栈的顺序「出栈压栈的过程」,例如先序遍历对二叉树进行遍历,暂存前,会把当前节点值存入到 result 中,在进行左子树遍历,一直遍历到为空再出栈,再以当前节点的右节点为目标执行相同的操作。

思路如下:

  • 取跟节点为目标节点,开始遍历
  • 1.访问目标节点值
  • 2.左子树入栈 -> 直至左子树为空的节点
  • 3.节点出栈,以右子树为目标节点,再依次执行1、2、3
function test2(root) {
    let stack = [];
    let result = [];
    while(root || stack.length > 0) {
        while(root) {
            result.push(root.val);
            stack.push(root);
            root = root.left;
        }
        root = stack.pop();
        root = root.right;
    }
    return result;
}

2 中序遍历

思路如下:

  • 取跟节点为目标节点,开始遍历
  • 1.左子树入栈 -> 直至左子树为空的节点
  • 2.节点出栈 -> 访问该节点
  • 3.以右子树为目标节点,再依次执行1、2、3
function test(root) {
    let result = [];
    let stack = [];
    while(root || stack.length > 0) {
        while(root) {
            stack.push(root);
            root = root.left;
        }
        root = stack.pop();
        result.push(root.val);
        root = root.right;
    }
    return result;
}

3 后序遍历

后序遍历和前序、中序有一点差别,出现差别的原因是因为遍历完左子树,如果当前遍历最后的一个节点有右子树,还需要遍历右子树。

function test(root) {
    const result = [];
    const stack = [];
    let last = null;
    while (root || stack.length > 0) {
        while (root) {
            stack.push(root);
            root = root.left;
        }
        root = stack[stack.length - 1];
        if (!root.right || root.right === last) {
            root = stack.pop();
            result.push(root.val);
            last = root;
            root = null;
        } else {
            root = root.right;
        }
    }
    return result;
}