javascript进阶必备的二叉树知识

·  阅读 314

js

对于程序猿(攻城狮)来说,初期可能很少有机会涉及数据结构和算法的相关工作,后期对相关业务也已经了解得相对熟悉了,各种各样的技术或多或少都已经用过或者了解过或者听说过了,那么这个时候我们是否应该去突破下自己的瓶颈呢?对于这一阶段的程序猿来说,应该要去了解下数据结构、设计模式、算法的相关知识。

在这里,我总结下我自己接触过的二叉树相关知识。

二叉树介绍

二叉树(Binary tree)是树形结构的一个重要类型。许多实际问题抽象出来的数据结构往往是二叉树形式,即使是一般的树也能简单地转换为二叉树,而且二叉树的存储结构及其算法都较为简单,因此二叉树显得特别重要。二叉树特点是每个结点最多只能有两棵子树,且有左右之分。

我们先来看一棵二叉树

二叉树

二叉树树的遍历

在二叉树中,树的遍历是一个非常有趣的事情,因为它有很多种遍历的方式:前序遍历、中序遍历、后序遍历、层次遍历。那接下来,我会一一介绍给大家。

// 这里用 js 对象的形式写一个简单的二叉树
var treenode = {
  value: 1,
  left: {
    value: 2,
    left: {
      value: 4,
    },
    right: {
      value: 5,
      left: {
        value: 7,
      },
      right: {
        value: 8,
      },
    },
  },
  right: {
    value: 3,
    right: {
      value: 6,
    },
  },
}
复制代码
  • 前序遍历

前序遍历(DLR),是二叉树遍历的一种,也叫做先根遍历、先序遍历、前序周游,可记做根左右。前序遍历首先访问根结点然后遍历左子树,最后遍历右子树。

// 递归实现
function preOrderTraversal(root) {
  var result = []
  function preOrderTraversalNode(node) {
    if (node) {
      result.push(node.value)
      if (node.left) {
        preOrderTraversalNode(node.left)
      }
      if (node.right) {
        preOrderTraversalNode(node.right)
      }
    }
  }
  preOrderTraversalNode(root)
  return result
}
复制代码
// 迭代实现
function preOrderTraversal(root) {
  var list = [],
      stack = []
      
  if (root) {
    stack.push(root)
  }
  
  while (stack.length > 0) {
    var curNode = stack.pop()
    list.push(curNode.value)
    if (curNode.right) {
      stack.push(curNode.right)
    }
    if (curNode.left) {
      stack.push(curNode.left)
    }
  }
  return list
}
复制代码
preOrderTraversal(treenode) // [1, 2, 4, 5, 7, 8, 3, 6]
复制代码
  • 中序遍历

中序遍历(LDR)是二叉树遍历的一种,也叫做中根遍历、中序周游。在二叉树中,中序遍历首先遍历左子树,然后访问根结点,最后遍历右子树。

// 递归实现
function inorderTraversal(root) {
  var result = []
  function inOrderTraversalNode(node) {
    if (node) {
      if (node.left) {
        inOrderTraversalNode(node.left)
      }
      result.push(node.value)
      if (node.right) {
        inOrderTraversalNode(node.right)
      }
    }
  }
  inOrderTraversalNode(root)
  return result
}
复制代码
// 迭代实现
function inorderTraversal(root) {
  var list = [],
      stack = []
      
  while (root || stack.length > 0) {
    while (root) {
      stack.push(root);
      root = root.left;
    }
    root = stack.pop();
    list.push(root.value);
    root = root.right;
  }
  return list;
}
复制代码
inorderTraversal(treenode) // [4, 2, 7, 5, 8, 1, 3, 6]
复制代码
  • 后序遍历

后序遍历(LRD)是二叉树遍历的一种,也叫做后根遍历、后序周游,可记做左右根。后序遍历有递归算法和非递归算法两种。在二叉树中,先左后右再根,即首先遍历左子树,然后遍历右子树,最后访问根结点。

// 递归实现
function postorderTraversal(root) {
  var result = []
  function postorderTraversalNode(node) {
    if (node) {
      if (node.left) {
        postorderTraversalNode(node.left)
      }
      if (node.right) {
        postorderTraversalNode(node.right)
      }
      result.push(node.value)
    }
  }
  postorderTraversalNode(root)
  return result
}
复制代码
// 迭代实现
function postorderTraversal(root) {
  var list = [],
      stack = []
      
  if (root) {
    stack.push(root)
  }
  
  while (stack.length > 0) {
    var curNode = stack.pop()
    list.unshift(curNode.value)
    if (curNode.left) {
      stack.push(curNode.left)
    }
    if (curNode.right) {
      stack.push(curNode.right)
    }
  }
  return list
}
复制代码
postorderTraversal(treenode) // [4, 7, 8, 5, 2, 6, 3, 1]
复制代码
  • 层次遍历

在二叉树中,从上往下遍历。

function levelorderTraversal(root) {
  const list = [];
  let stack = [];
  if (root) {
    stack.push(root);
  }
  while (stack.length > 0) {
    const newStack = [];
    for (let i = 0; i < stack.length; i++) {
      const curNode = stack[i];
      list.push(curNode.value);
      if (curNode.left) {
        newStack.push(curNode.left);
      }
      if (curNode.right) {
        newStack.push(curNode.right);
      }
    }
    stack = newStack;
  }
  return list;
}
复制代码
levelorderTraversal(treenode) // [1, 2, 3, 4, 5, 6, 7, 8]
复制代码
  • 对称二叉树判断

判断两颗二叉树是否对称

const isSymmetrical = (treenodeA, treenodeB) => {
  if (!treenodeA && !treenodeB) {
    return true
  }
  if (!treenodeA || !treenodeB) {
    return false
  }
  if (treenodeA.value !== treenodeB.value) {
    return false
  }
  return isSymmetrical(treenodeA.left, treenodeB.right) && isSymmetrical(treenodeA.right, treenodeB.left)
}
复制代码
const treenodeB = {
  value: 1,
  left: {
    value: 3,
    left: {
      value: 6,
    },
  },
  right: {
    value: 2,
    left: {
      value: 5,
      left: {
        value: 8,
      },
      right: {
        value: 7,
      },
    },
    right: {
      value: 4,
    },
  },
}

isSymmetrical(treenode, treenodeB) // true
复制代码

今天就介绍到这里了。之后,我也会介绍实现二叉树、二叉树搜索、移除节点等等方法...

分类:
前端
标签:
分类:
前端
标签: