前端数据结构中的——树

611 阅读3分钟

树是什么?

在生活中 ‘树’ 肯定不陌生,随处可见,桃树、梨树、杨树、柳树·····

在计算机科学里面树是👇

  • 一种分层数据的抽象模型
  • 前端工作中常见的树有:DOM 树、级联选择、树形控件·····
  • Js 中没有树,但是我们可以通过 Object 和 Array 构建树
  • 树的常用操作:深度/广度优先遍历,先中后序遍历

深度/广度优先遍历

深度优先遍历:尽可能深的搜索树的分支

  • 算法口诀:

    • 访问根节点
    • 对根节点的 children 挨个进行深度优先遍历

广度优先遍历:先访问离根节点进的节点

  • 算法口诀:

    • 新建一个队列,让根节点入队
    • 把对头出队访问
    • 把对头的children挨个入队
    • 重复二、三,直至队列为空

const tree = {
    val: 'a',
    children:[
        {
            val: 'b',
            children:[ { val: 'd' }, { val: 'e' } ]
        },{
            val: 'c',
            children:[ { val: 'f' }, { val: 'g' } ]
        },
    ]
}

// 深度优先遍历 coding
const depth = (root) => {
    console.log(root.val,'Depth');  // a, b, d, e, c, f, g
    root.children.forEach(depth);
}
depth(tree);

// 广度优先遍历 coding
const readth = (root) => {
    const q = [root];
    while (q.length) {
        const n = q.shift();
        console.log(n.val, 'readth'); // a, b, c, d, e, f, g
        n.children.forEach(child => {
            q.push(child);
        })
    }
}
readth(tree);

二叉树中的先中后序优先遍历

二叉树是?

  • 树中的每个节点最多只能有两个子节点
  • 在JavaScript中通常使用 Object 来模拟二叉树

先序遍历

  • 访问节点
  • 对根节点的左子树进行先序遍历
  • 对根节点的右子树进行先序遍历

中序遍历

  • 对根节点的左子树进行中序遍历
  • 访问 根 节点
  • 对根节点的右子树进行中序遍历

后序遍历

  • 对根节点的左子树进行中序遍历
  • 对根节点的右子树进行中序遍历
  • 访问节点
const binaryTree = {
    val: 1,
    left: {
        val: 2,
        left: { val: 4, left: null, right: null },
        right: { val: 5, left: null, right: null }
    },
    right: {
        val: 3,
        left: { val: 6, left: null, right: null },
        right: { val: 7, left: null, right: null }
    },
};

///////////// 先序遍历  

// 1. 递归方法
function preorder1 (root) {
    if (!root) return;
    console.log(root.val) // 1,2,4,5,3,6,7 
    preorder(root.left);
    preorder(root.right);
}
preorder1(binaryTree);

// 2. 非递归方法
function preorder2 (root) {
    if (!root) return;
    const stack = [root];
    while (stack.length) {
        const n = stack.pop();
        console.log(n.val) // 1,2,4,5,3,6,7 
        if (n.right) stack.push(n.right);
        if (n.left) stack.push(n.left) 
    }
}
preorder2(binaryTree);


//////////// 中序遍历

// 1. 递归方法
function inorder1 (root) {
    if (!root) return;

    inorder(root.left);

    console.log(root.val) // 4, 2, 5, 1, 6, 3, 7

    inorder(root.right);

}

inorder1(binaryTree);

// 2. 非递归方法
function inorder2 (root) {
    if (!root) return;
    const stack = [];
    let p = root;
    while (stack.length || p) {
        while (p) {
            stack.push(p);
            p = p.left;
        }
        const n = stack.pop();
        console.log(n.val) // 4, 2, 5, 1, 6, 3, 7
        p = n.right;
    }
}
inorder2(binaryTree);


//////////// 后序遍历

// 1. 递归方法
function endorder1 (root) {
    if (!root) return;
    inorder(root.left);
    inorder(root.right);
    console.log(root.val) // 4, 5, 2, 6, 7, 3, 1
}
endorder1(binaryTree);

// 2. 非递归方法
function endorder2 (root) {
    if (!root) return;
    const stack = [root];
    const outputStack = [];
    while (stack.length) {
        const n = stack.pop();
        outputStack.push(n);
        if (n.left) stack.push(n.left);
        if (n.right) stack.push(n.right);
    }
    while (outputStack.length) {
        const n = outputStack.pop();
        console.log(n.val) // 4, 5, 2, 6, 7, 3, 1
    }
}
endorder2(binaryTree);

力扣 104-二叉树的最大深度

题目 给定一个二叉树,找出其最大深度。二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。

说明: 叶子节点是指没有子节点的节点。

示例:给定二叉树 [3,9,20,null,null,15,7],

    3
   / \
  9  20
    /  \
   15   7
返回它的最大深度 3 。

步骤:

  • 给定一个变量,记录最大深度;
  • 深度优先遍历整棵树,并记录每个节点的层级,同时不断刷新最大深度这个变量
  • 遍历结束后,返回最大深度这个变量
// 使用了 深度优先遍历 方法
var maxDepth = function(root) {
    let res = 0;
    const dsf = (n, l) => {
        if(!n) return;
        if(!n.left && !n.right) {
            res = Math.max(res, l);
        }
        dsf(n.left, l + 1);
        dsf(n.right, l +1);
    };
    dsf(root, 1);
    return res;
};