数据结构-树

128 阅读2分钟
特点

一种分层数据的抽象模型

操作
  • 深度优先遍历
  • 广度优先遍历
  • 二叉树的前/中/后序遍历
演示
      // 深度优先遍历
      // 尽可能深的搜索书的分支
      // 访问根节点,然后对根节点的子节点挨个进行深度遍历(递归);
      const dfs = (root) => {
        console.log(root.val);
        root.children.forEach(dfs);
      };

      // 广度优先遍历
      // 新建一个队列,把根节点入队,
      // 把对头出对并访问,把对头的children挨个入队;(重复操作,直到队列为空)
      const bfs = (root) => {
        const queue = [root];
        while (queue.length > 0) {
          const node = queue.shift();
          console.log(node.val);
          node.children.forEach((item) => {
            queue.push(item);
          });
        }
      };

二叉树的前/中/后序遍历

      // 先序遍历(根左右)
      // 操作:先访问根节点,对根节点的左子树先序遍历,对根节点的右子树先序便利;
      const preorder = (root) => {
        if (!root) return;
        console.log(root.val);
        preorder(root.left);
        preorder(root.right);
      };
      
      //非递归版
      const inorder = (root) => {
        if (!root) return;
        const stack = [root];
        while (stack.length) {
          const node = stack.pop();
          console.log(node.val);
          if (node.right) stack.push(node.right);
          if (node.left) stack.push(node.left);
        }
      };
      
      
      // 中序遍历(左根右)
      // 操作:先访问根节点的左子树,进行中序便利,访问根节点,对根节点的右子树进行中序便利;
      const inorder = root =>{
          if (!root) return ;
          inorder(root.left);
          console.log(root.val);
          inorder(root.right);
      }
      // 非递归版
       const inorder = (root) => {
        if (!root) return;
        const stack = [];
        let p = root;
        while (stack.length || p) {
          while (p) {
            stack.push(p);
            p = p.left;
          }
          const node = stack.pop();
          console.log(node.val);
          p = node.right;
        }
      };

      // 后序遍历(左右根)
      // 操作:对根节点的左子树后序遍历,对根节点的右子树后序遍历,访问根节点
      const postorder = root =>{
          if(!root) return ;
          postorder(root.left);
          postorder(root.right);
          console.log(root.val);
      }
      
      //非递归版
      const postorder = (root) => {
        if (!root) return;
        const stack = [root];
        const outputStack = [];
        while (stack.length) {
          const node = stack.pop();
          outputStack.push(node);
          if (node.left) stack.push(node.left);
          if (node.right) stack.push(node.right);
        }
        while (outputStack.length) {
          const node = outputStack.pop();
          console.log(node.val);
        }
      };
练习题

104. 二叉树的最大深度

//  求最大的深度,考虑使用深度优先遍历,深度优先遍历中,记录每个节点的层级,找出最大的层级
var maxDepth = function(root) {
    let res = 0;
    const dfs = (root,len) =>{
        if (!root) return;
        res = Math.max(len,res); // if (!root.left && !root.right) res = Math.max(len, res);
        if (root.left) dfs(root.left,len+1);
        if (root.right) dfs(root.right,len+1);
    }
    dfs(root,1);
    return res;
};

111. 二叉树的最小深度

      // 求最小的深度,优先考虑广度优先遍历;遇到叶子结点,停止遍历,返回节点层级;
      var minDepth = function (root) {
        if (!root) return 0;
        const queue = [[root, 1]];
        while (queue.length) {
          const [node, len] = queue.shift();
          if (!node.left && !node.right) return len;
          if (node.left) queue.push([node.left, len + 1]);
          if (node.right) queue.push([node.right, len + 1]);
        }
      };

102. 二叉树的层序遍历

      var levelOrder = function (root) {
        // 层序遍历就是广度优先遍历
        // 遍历的时候记录当前节点所处的层级,将其节点按层级添加到数组中;
        if (!root) return [];
        const res = [];
        const queue = [[root, 0]];
        while (queue.length > 0) {
          const [node, len] = queue.shift();
          if (res[len]) { // 当前层级是否存在
            res[len].push(node.val);
          } else {
            res[len] = [node.val];
          }
          if (node.left) queue.push([node.left, len + 1]);
          if (node.right) queue.push([node.right, len + 1]);
        }
        return res;
      };
var levelOrder = function(root) {
    if(!root) return [];
    const queue = [root];
    const res = [];
    while(queue.length){
        let len = queue.length;
       res.push([])
        while(len--){
            const node = queue.shift();
            res[res.length-1].push(node.val);
            if (node.left) queue.push(node.left);
            if (node.right) queue.push(node.right);
        }
    }
    return res;
};

112. 路径总和

       // 深度优先遍历,记录当前路径节的节点值的和,判断当前节点是否和目标节点相当;
      var hasPathSum = function (root, targetSum) {
        let res = false;
        if (!root) return res;
        const dfs = (root, val) => {
          if (!root) return;
          if (!root.left && !root.right && val === targetSum) res = true;
          if (root.left) dfs(root.left, root.val + val);
          if (root.right) dfs(root.right, root.val + val);
        };
        dfs(root, root.val);
        return res;
      };