(算法)二叉树先序、后序、中序遍历及二叉树的层次遍历、翻转

82 阅读2分钟

先序遍历

给定一个二叉树,返回它的前序(先序)遍历序列。

示例:

输入: [1,null,2,3]

1
 \ 
  2 
 / 
3

输出: [1,2,3]
// 二叉树对象结构
function TreeNode(val) {
  this.val = val; 
  this.left = this.right = null;
 }
// 树结构
const root = { 
    val: "A", 
    left: { 
      val: "B", 
      left: { val: "D" }, 
      right: { val: "E" } 
    }, 
    right: { 
      val: "C", 
      right: { val: "F" } 
    } 
 };

题解:

/** 
* @param {TreeNode} root
* @return {number[]}
*/
const preorderTraversal = (root) => {
    const res = [];
    
    //处理边界
    if(!root){
      return res;
    }
    
    //栈
    const stack = [];
    stack.push(root);
    
    while(stack.length){
      // 出栈
      const cur = stack.pop();
      // 保存值
      res.push(cur.val);
      
      //right 入栈
      if(cur.right){
        stack.push(cur.right);
      }
      // left 入栈
      if(cur.left){
        stack.push(cur.left);
      }
    }
    
    return res;
}

规则:

根->左->右,合理地安排入栈和出栈的时机、使栈的出栈序列符合二叉树的前序遍历规则

后序遍历

反转从位置 m 到 n 的链表。请使用一趟扫描完成反转。

/** 
* @param {TreeNode} root
* @return {number[]}
*/
const postorderTraversal = (root) => {
    const res = [];
    
    //处理边界
    if(!root){
      return res;
    }
    
    //栈
    const stack = [];
    stack.push(root);
    
    while(stack.length){
      // 出栈
      const cur = stack.pop();
      // 保存值
      res.unshift(cur.val);
      
      // left先入栈right后入栈,保持执行顺序先右后左
      // unshift保证结果为 左 -> 右 -> 根
      // left 入栈
      if(cur.left){
        stack.push(cur.left);
      }
      
      //right 入栈
      if(cur.right){
        stack.push(cur.right);
      }
    }
    
    return res;
}

规则:

左 -> 右 -> 根,从res结果数组上入手,unshift进res的头部。

中序遍历

题解:

/** 
* @param {TreeNode} root
* @return {number[]}
*/
const inorderTraversal = (root) => {
    const res = [];
    
    //栈
    const stack = [];
    
    //游标
    let cur = root;
    
    while(cur || stack.length){
    
      // 一直找left入栈
      while(cur){
        //当前节点入栈
        stack.push(cur);
        cur = cur.left;
      }
      
      // left全部入栈后出栈
      cur = stack.pop();
      
      //此时为根节点,保存当前节点值
      res.push(cur.val)
      
      //对右节点进行遍历同样步骤
      cur = cur.right;
    }
    
    return res;
}

规则:

左 -> 根 -> 右, 一路向左,然后回溯。

层次遍历

给你一个二叉树,请你返回其按 层序遍历 得到的节点值。 (即逐层地,从左到右访问所有节点)。

示例:

二叉树:[3,9,20,null,null,15,7],

  3
 / \
9  20
  /  \
 15   7

返回其层次遍历结果:  
[  
[3],  
[9,20],  
[15,7]  
]

题解:

/** 
* @param {TreeNode} root
* @return {number[]}
*/
const levelOrder = (root) => {
    const res = [];
    
    //处理边界
    if(!root){
      return res;
    }
    
    //队
    const queue = [];
    queue.push(root);
    
    while(queue.length){
      // 保存当前层的节点
      const levelVal = [];
      //当前层的元素长度
      const len = queue.length;
      for(let i=0; i<len; i++){
        //出队
        const top = queue.shift();
        //保存
        levelVal.push(top.val);
        
        //入队
        if(top.left){
          queue.push(top.left);
        }
        if(top.right){
          queue.push(top.right);
        }
      }
      
      // 保存结果
      res.push(levelVal);
    }
    
    return res;
}

规则:

BFS使用队列,记录下这一层结点个数,然后将这个数量范围内的元素push进同一个数组

翻转二叉树

翻转一棵二叉树。

示例:

输入:

     4
   /   \
  2     7
 / \   / \
1   3 6   9

输出:
     4
   /   \
  7     2
 / \   / \
9   6 3   1

题解:

/** 
* @param {TreeNode} root
* @return {TreeNode}
*/
const invertTree = (root) => {
  if(!root){
    return root;    
  }
  
  let left = invertTree(root.left);
  let right = invertTree(root.right);
  
  // 回溯时交换
  root.left = right;
  root.right = left;
  // 返回
  return root;
}

规则:

递归的方式,遍历树中的每一个结点,并将每一个结点的左右孩子进行交换。