算法 树(含例题)

  • JS中没有树,但是可以用Object和Array构造树
  • 树的常用操作:深度/广度优先遍历、先中后序遍历

树的深度与广度优先遍历

简单理解:

将 树 比作 书

深度遍历:从第一页看到最后一页

广度遍历:先看目录,再看内容

深度优先遍历

深度优先遍历的算法口诀:

  • 访问根节点
  • 对根节点的children挨个进行深度优先遍历
// 深层遍历
const tree = {
    val:'a',
    children:[
        {
            val:'b',
            children:[
                {
                    val:'c',
                    children:[]
                }
            ]
        },{
            val:'d',
            children:[
                {
                    val:'e',
                    children:[]
                }
            ]
        }
    ]
}

const dfs = (root) => {
    console.log(root.val)
    root.children.forEach(children => dfs(children))
}

dfs(tree)
//> a
//> b
//> c
//> d
//> e

广度优先遍历

  • 新建一个队列,把根节点入队
  • 把队头出队并访问
  • 把队头的children挨个入队
  • 重复第二、三步,直到队列为空
const tree = {
    val:'a',
    children:[
        {
            val:'b',
            children:[
                {
                    val:'c',
                    children:[]
                }
            ]
        },{
            val:'d',
            children:[
                {
                    val:'e',
                    children:[]
                }
            ]
        }
    ]
}

const bfs = (root) => {
    const q = [root]
    while(q.length > 0){
        const n = q.shift()
        console.log(n)
        n.children.forEach(child => {
            q.push(child)
        })
    }
}

bfs(tree)

二叉树

  • 树中每个节点最多只能由两个子节点
  • 在JS中通常用Object来模拟二叉树

先序遍历

  • 访问根节点
  • 对根节点的左子树进行先序遍历
  • 对根节点的右子树进行先序遍历
const preorder = (root) => {
    if (!root) return;
    console.log(root.val)
    preorder(root.left)
    preorder(root.right)
}

中序遍历

  • 对根节点的左子树进行中序遍历
  • 访问根节点
  • 对根节点的右子树进行中序遍历
const inorder = root => {
    if(!root) return
    inorder(root.left)
    console.log(root.val)
    inorder(root,right)
}

后序遍历

  • 对根节点的左子树进行后序遍历
  • 对根节点的右子树进行后序遍历
  • 访问根节点
const postorder = root => {
    if(!root) return 
    postorder(root.left)
    postorder(root.right)
    console.log(root.val)
}

非递归版的先中后遍历

主要是通过栈来实现,先进后出,后进先出

先序遍历

const preorder = root => {
    if(!root) return ;
    const stack = [root]
    while(stack.length) {
        // 弹出元素
        const n = stack.pop()
        console.log(n.val)
        // 注意入栈的顺序,先进后出
        if(n.right) stack.push(n.right)
        if(n.left) stack.push(n.left)
    }
}

中序遍历

const inorder = 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)
        // 访问节点
        p = n.right
    }
}

后续遍历

后序遍历:左右根

先序遍历:根左右

思路:

将前序号排列逆向存储

const postorder = root => {
    if(!root) return
    const outputStack = []
    const stack = []
    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()
        
    }
}

104 二叉树的最大深度

编写遍历树的函数——dfs()

参数:

  • n:当前节点
  • l:深度

dfs(root,1),传入的深度为1,因为只要根节点有值,那么深度最小就为1

var maxDepth = function(root) {
    // 记录深度
    let deep = 0
    const dfs = (n,l) => {
        if(!n)return
        deep = Math.max(deep, l)
        dfs(n.left,l+1)
        dfs(n.right,l+1)
    }
    dfs(root,1)
    return deep
};

111 二叉树的最小深度

  • 求最小深度,考虑使用广度优先遍历
  • 在广度优先遍历中,遇到叶子节点,停止遍历,返回节点层级

q中存储的是数组,[节点,层级]

var minDepth = function(root) {
    if(!root) {return 0;}
    const q = [[root,1]];
    while(q.length){
        const [n,l] = q.shift();
        if(!n.left && !n.right){
            return l;
        }
        if(n.left)q.push([n.left,l+1]);
        if(n.right)q.push([n.right,l+1]);
    }
};

102 二叉树的层序遍历

  • 层序遍历顺序就是广度优先遍历
  • 不过在遍历时候需要记录当前节点所在的层级,方便将其添加到不同的数组中
var levelOrder = function(root) {
    if(!root) return []
    let q = [[root,0]]
    let global = []
    while(q.length){
        const [n,l] = q.shift()
        if(!global[l]){
            global.push([n.val])
        }else{
            global[l].push(n.val)
        }
        if(n.left) q.push([n.left,l+1])
        if(n.right) q.push([n.right,l+1])
    }
    return global
};

前端与树:遍历SON的所有节点值

const json = {
    a:{ b: { c: 1} },
    d:[1,2]
}

const dfs = (n, path) => {
    console.log(n,path)
    Object.keys(n).forEach(k => {
        dfs(n[k],path.concat(k))
    })
}

dfs(json,)
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值