js中的二叉树

68 阅读3分钟

二叉树的结构定义

function TreeNode(val,left,right){
this.val=(val===undefined? 0:val)
this.left=(left===undefined? null:left)
this.right=(right===undefined? null:right)
}
  1. 确定递归函数的参数和返回值:  确定哪些参数是递归的过程中需要处理的,那么就在递归函数里加上这个参数, 并且还要明确每次递归的返回值是什么进而确定递归函数的返回类型。
  2. 确定终止条件:  写完了递归算法, 运行的时候,经常会遇到栈溢出的错误,就是没写终止条件或者终止条件写的不对,操作系统也是用一个栈的结构来保存每一层递归的信息,如果递归没有终止,操作系统的内存栈必然就会溢出。
  3. 确定单层递归的逻辑:  确定每一层递归需要处理的信息。在这里也就会重复调用自己来实现递归的过程。

二叉树的前序遍历

var preorderTraversal = function(root) {
    let reslut=[]
    function dfs(node){
        if(node===null)  return
        reslut.push(node.val)
        dfs(node.left)
        dfs(node.right)
    }
    dfs(root)
    return reslut 
};

二叉树的中序遍历

var inorderTraversal = function(root) {
    if(!root) return []
    let result=[]
    result=result.concat(inorderTraversal(root.left))
    result.push(root.val)
    result=result.concat(inorderTraversal(root.right))
    return result
};

二叉树的后序遍历

var postorderTraversal = function(root) {
   
    if(!root) return []
    let result=[]
    result=result.concat(postorderTraversal(root.left))
    result=result.concat(postorderTraversal(root.right))
    result.push(root.val)
    return result

};

二叉树的层序遍历

size 使用队列去模拟 size就是可以控制,当前层有几个元素,后续就弹出几个元素

var levelOrder = function(root) {
    let result=[]  //存放最终结果
    if(root===null) return []
    let queue=[root]   //模拟队列,存放的是节点!!!
    while(queue.length!==0){
        let curlevel=[]  //存放每一层的结果
        let len=queue.length
        for(let i=0;i<len;i++){
            let node=queue.shift()  //取出队头节点
            curlevel.push(node.val) //将节点值放入当前数组
            node.left&&queue.push(node.left)  //放入当前节点的左右孩子
            node.right&&queue.push(node.right)
        }
        result.push(curlevel) //将当前层的结果存入最终的数组中
    }
    return result 
};

翻转二叉树 226. 翻转二叉树 - 力扣(LeetCode)

var invertTree = function(root) {
    if(root===null){
        return  null
    }
    let temp=root.right            //递归的前序遍历的方法
    root.right=invertTree(root.left)  //主要就是交换两个左右孩子
    root.left=invertTree(temp)
    return root
};

对称二叉树 101. 对称二叉树 - 力扣(LeetCode)

var isSymmetric = function(root) {
//后序遍历  递归
   function mirro(left,right){
    if(left===null&&right!==null) return false   //递归的终止条件
    if(left!==null&&right===null) return false
    if(left===null&&right===null) return true
    if(left.val!==right.val) return false
    
    if(left.val===right.val){         //进行左右对比
      return   mirro(left.right,right.left)&&mirro(left.left,right.right)
    } 
   }
   if(root===null) return true
   return  mirro(root,root)

};

二叉树的节点数量 222. 完全二叉树的节点个数 - 力扣(LeetCode)

var countNodes = function(root) {
    
  if(root===null) return 0       //后续遍历
  let left=countNodes(root.left)
  let right=countNodes(root.right)
  return left+right+1
    
};

中序遍历和后续遍历 构造二叉树
左跟右 左右根

注意点:slice方法是左闭右开的
特别需要注意的地方就是 区间问题
var buildTree = function(inorder, postorder) {
    if(postorder.length===0) return null  
    let rootval=postorder.pop()  //从后序节点获取根节点的值,最后一个元素
    let rootindex=inorder.indexOf(rootval) //获取根节点在中序遍历的下标
    let root=new TreeNode(rootval)  //创建根节点
root.left=buildTree(inorder.slice(0,rootindex),postorder.slice(0,rootindex))//创建左子树
root.right=buildTree(inorder.slice(rootindex+1),postorder.slice(rootindex))//创建右子树
    return root
    
};

前序遍历和中序遍历构造二叉树

var buildTree = function(preorder, inorder) {
    if(preorder.length===0||inorder.length===0) return null
    let rootval=preorder.shift()
    let rootindex=inorder.indexOf(rootval)
    let root=new TreeNode(rootval)
    root.left=buildTree(preorder.slice(0,rootindex),inorder.slice(0,rootindex))
    root.right=buildTree(preorder.slice(rootindex),inorder.slice(rootindex+1))
    return root
};

重点在于,切割的索引,因为中序数组,没有扔出元素,所以,需要跳过这个中间元素 slice左闭右开 前序或者 后续 是需要接上元素的下标的