一文弄懂二叉树三种顺序的迭代与递归遍历的异同

63 阅读2分钟

二叉树的遍历(JS)

二叉树的递归遍历(先序、中序、后序)

/**
 * Definition for a binary tree node.
 * function TreeNode(val, left, right) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.left = (left===undefined ? null : left)
 *     this.right = (right===undefined ? null : right)
 * }
 */
/**
 * @param {TreeNode} root
 * @return {number[]}
 */
var preorderTraversal = function(root) {
    const res = []
    const preorder = function(root) {
        // 终止条件
        if(root === null) return
        // 先序遍历, 中序、后序同理,调整顺序即可
        res.push(root.val)
        preorder(root.left)
        preorder(root.right)
    }
    preorder(root)
    return res
};

二叉树的迭代遍历(先序、中序、后序)

先分别将先序中序后序的迭代遍历代码贴在这里

先序迭代遍历

/**
 * Definition for a binary tree node.
 * function TreeNode(val, left, right) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.left = (left===undefined ? null : left)
 *     this.right = (right===undefined ? null : right)
 * }
 */
/**
 * @param {TreeNode} root
 * @return {number[]}
 */
var preorderTraversal = function(root) {
    // 定义遍历数组
    let res = []
    if(!root) return res;
    // 定义递归栈
    const stack = []
    while(stack.length || root) {
        if(root) {
            stack.push(root)
            res.push(root.val)
            root = root.left
        } else {
            root = stack.pop()
            root = root.right
        }
    }
    return res
};

中序迭代遍历

/**
 * Definition for a binary tree node.
 * function TreeNode(val, left, right) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.left = (left===undefined ? null : left)
 *     this.right = (right===undefined ? null : right)
 * }
 */
/**
 * @param {TreeNode} root
 * @return {number[]}
 */
var preorderTraversal = function(root) {
    let res = []
    if(!root) return res;
    const stack = []
    while(stack.length || root) {
        if(root) {
            stack.push(root)
            root = root.left
        } else {
            root = stack.pop()
            //与先序迭代遍历几乎一样,唯一的区别是将遍历语句移到了此处
            res.push(root.val)
            root = root.right
        }
    }
    return res
};

后序迭代遍历

 * Definition for a binary tree node.
 * function TreeNode(val, left, right) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.left = (left===undefined ? null : left)
 *     this.right = (right===undefined ? null : right)
 * }
 */
/**
 * @param {TreeNode} root
 * @return {number[]}
 */
var postorderTraversal = function(root) {
    const res = []
    const stack = []
    let cur = root
    // 与先序和中序遍历不同,由于后序遍历需要经过父节点两次,且操作不同,
    // 因此需要定义一个前缀节点,以区分是第几次到达父节点。
    let pre = null
    while(stack.length || cur) {
        if(cur) {
            stack.push(cur)
            cur = cur.left
        } else {
            cur = stack[stack.length - 1]
            //判断是第一次到该节点还是第二次
            if(cur.right && pre !== cur.right) {
            //第一次到该节点 
                cur = cur.right   
            } else {
            //第二次到该节点 
                stack.pop()
                res.push(cur.val)
                pre = cur
                cur = null
            }
        }
    }
    return res
};

总结:

1.递归遍历可以采用几乎完全一样的模板,只需要调整遍历顺序即可;

2.迭代遍历中采用的模板大致相同,都依靠设置了一个辅助栈进行遍历,其中后序遍历还需要定义一个pre指针来区分是第几次经过父节点;

3.先序和中序迭代遍历仅有的区别在于什么时候将节点推入res数组,因此中序遍历相对先序遍历只改动了一行代码;

4.后序迭代遍历相对先序和中序在遍历左子树时操作相同,当遍历到父节点时需要判断是第一次还是第二次到达父节点,若第一次到达则继续遍历右子树,若是第二次则需要将节点值推入res数组并设置pre指针。