代码随想录算法训练营第十三天 | 二叉树理论笔记

61 阅读3分钟

理论

文章链接

手写二叉树

class TreeNode{
  public val:number
  public left:TreeNode|null
  public right:TreeNode|null
  constructor(val?:number,left?:TreeNode,right?:TreeNode){
    this.val=(val===undefined)?0:val
    this.left=(left===undefined)?null:left
    this.right=(right===undefined)?null:right
  }
}

二叉树的递归写法

文章链接

写递归函数的步骤

  1. 确定递归函数的参数和返回值
  2. 确定终止条件
  3. 确定单层递归的逻辑

二叉树的前中后遍历

前序遍历

function preorderTraversal(root: TreeNode | null): number[] {
    let res:number[]=[]
   const foo:(root:TreeNode|null)=>void=(root: TreeNode | null)=>{
           //终止条件
           if(root==null) return
           //中
           res.push(root.val)
           //左
           foo(root.left)
           //右
           foo(root.right)
   }
   foo(root)
   return res
};

后序遍历

function postorderTraversal(root: TreeNode | null): number[] {
  let res:number[]=[]
  const foo:(root: TreeNode | null)=>void=(root: TreeNode | null)=>{
      //终止条件
      if(root==null) return
      //左
      foo(root.left)
      //右
      foo(root.right)
      //中
      res.push(root.val)
  }
  foo(root)
  return res
};

中序遍历

function inorderTraversal(root: TreeNode | null): number[] {
    let res:number[]=[]
    const foo:(root: TreeNode | null)=>void=function(root: TreeNode | null){
        //终止条件
        if(root==null) return
        //左
        foo(root.left)
        //中
        res.push(root.val)
        //右
        foo(root.right)
    }
    foo(root)
    return res
};

二叉树的迭代法

文章链接

迭代写法

前序遍历

看完文章后前序遍历比较简单,因为处理顺序和压入栈的顺序一致,前序遍历是中左右,但是利用单调栈的话,要变成中右左,因为栈是后进先出的。代码如下:

function preorderTraversal(root: TreeNode | null): number[] {
  if(!root) return []
  let res:number[]=[]
  let stack:TreeNode[]=[]
  stack.push(root)
  while(stack.length!=0){
      let node:TreeNode=stack.pop()!
      res.push(node.val)//中
      if(node.right) stack.push(node.right);//右
      if(node.left) stack.push(node.left);//左
  }
 return res
};

后序遍历

后序遍历与前序遍历类似,后序是左右中,所以可以把前序遍历的代码变一下,例如代码随想录中的这张图:

image.png 代码如下:

function postorderTraversal(root: TreeNode | null): number[] {
  if(!root) return []
  let res:number[]=[]
  let stack:TreeNode[]=[]
  stack.push(root)
  while(stack.length!=0){
      let node:TreeNode=stack.pop()!
      res.push(node.val)//中
      //把中右左的遍历顺序变为中左右 (栈是后进先出的)
      if(node.left) stack.push(node.left);//左
      if(node.right) stack.push(node.right);//右
  }
 return res.reverse()
};

中序遍历

中序遍历比较复杂,因为处理节点的顺序和入栈的顺序不一致,所以需要利用指针来完成中序遍历,代码如下:

function inorderTraversal(root: TreeNode | null): number[] {
  if(!root) return []
  let res:number[]=[]
  let stack:TreeNode[]=[]
  let curr:TreeNode=root
  stack.push(root)
  while(stack.length>0||curr){
     if(curr!=null){//左
       if(curr.left) stack.push(curr.left);
       curr=curr.left!
     }else{
         let node:TreeNode=stack.pop()!
         res.push(node.val)//中
         curr=node.right! //右
         if(curr) stack.push(curr)
     }
  }
  return res
};

二叉树的统一迭代法

文章链接

统一的迭代法其实就是用了null作为标记,null的前一个就是要输出的节点

中序遍历

function inorderTraversal(root: TreeNode | null): number[] {
  let res:number[]=[]
  let stack:(TreeNode|null)[]=[]
  if(root!=null)stack.push(root)
  while(stack.length>0){
      let node:TreeNode|null=stack.pop() as (TreeNode|null)
      if(node!=null){
          if(node.right) stack.push(node.right) //右
          stack.push(node) //中
          stack.push(null) //标记
          if(node.left) stack.push(node.left)//左
      }else{
          node=stack.pop()!
          res.push(node.val)
      }
  }
  return res
};

前序遍历

function preorderTraversal(root: TreeNode | null): number[] {
  let res:number[]=[]
  let stack:(TreeNode|null)[]=[]
  if(root!=null)stack.push(root)
  while(stack.length>0){
      let node:TreeNode|null=stack.pop() as (TreeNode|null)
      if(node!=null){
          if(node.right) stack.push(node.right) //右
          if(node.left) stack.push(node.left)//左
          stack.push(node) //中
          stack.push(null) //标记
      }else{
          node=stack.pop()!
          res.push(node.val)
      }
  }
  return res
};

后序遍历

function postorderTraversal(root: TreeNode | null): number[] {
  let res:number[]=[]
  let stack:(TreeNode|null)[]=[]
  if(root!=null)stack.push(root)
  while(stack.length>0){
      let node:TreeNode|null=stack.pop() as (TreeNode|null)
      if(node!=null){
           stack.push(node) //中
          stack.push(null) //标记
          if(node.right) stack.push(node.right) //右
          if(node.left) stack.push(node.left)//左
      }else{
          node=stack.pop()!
          res.push(node.val)
      }
  }
  return res
};

今日总结

今日主要以理论为主,主要是熟悉二叉树中的迭代法和递归法,其中统一的迭代法得多加练习和查看,今日耗时2.5小时