二叉树遍历

434 阅读2分钟
leetcode题目
144.二叉树的前序遍历
145.二叉树的后序遍历
94.二叉树的中序遍历
102.二叉树的层序遍历

深度优先遍历(DFS)

DFS分为前序遍历、中序遍历和后序遍历(相对于根节点的访问时机)

网络图

const tree = {
  val: 'A',
  left: {
    val: 'B',
    left: {
      val: 'D'
    },
    right: {
      val: 'E'
    }
  },
  right: {
    val: 'C',
    left: {
      val: 'F'
    },
    right: {
      val: 'G'
    }
  }
}

1、递归方法

前序遍历

var preorderTraversal = function(root) {
  const result = []
  const depth = (root) => {
    if (root === null) return
    result.push(root.val)               // 中
    if (root.left) depth(root.left)     // 左
    if (root.right) depth(root.right)   // 右
  }
  depth(root)
  return result
};

中序遍历

var inorderTraversal = function(root) {
  const result = []
  const depth = (root) => {
    if (root === null) return
    if (root.left) depth(root.left)     // 左
    result.push(root.val)               // 中
    if (root.right) depth(root.right)   // 右
  }
  depth(root)
  return result
};

后序遍历

var postorderTraversal = function(root) {
  const result = []
  const depth = (root) => {
    if (root === null) return
    if (root.left) depth(root.left)     // 左
    if (root.right) depth(root.right)   // 右
    result.push(root.val)               // 中
  }
  depth(root)
  return result
};

递归方法中3种不同遍历就是对根节点的访问先后顺序

2、迭代方法

递归的实现就是:每一次递归调用都会把函数的局部变量、参数值和返回地址等压入调用栈中,迭代就是显式地用一个队列保存调用栈

前序遍历

var preorderTraversal = function(root) {
  const result = []
  if (root === null) return result
  let queue = [root]
  while (queue.length) {
    const target = queue.pop()
    if (target.right) {
      queue.push(target.right)
    }
    if (target.left) {
      queue.push(target.left)
    }
    result.push(target.val)
  }
  return result
}

后序遍历

var postorderTraversal = function(root) {
  const result = []
  if (root === null) return result
  const queue = [root]
  while (queue.length) {
    const target = queue.pop()
    result.unshift(target.val)
    if (target.left) {
      queue.push(target.left)
    }
    if (target.right) {
      queue.push(target.right)
    }
  }
  return result
};

中序遍历

中序遍历不能和前序遍历通用,因为前序遍历的顺序是中左右,先访问的元素是中间节点,要处理的元素也是中间节点,所以刚刚才能写出相对简洁的代码,因为要访问的元素和要处理的元素顺序是一致的,都是中间节点。

中序遍历,中序遍历是左中右,先访问的是二叉树顶部的节点,然后一层一层向下访问,直到到达树左面的最底部,再开始处理节点(也就是在把节点的数值放进result数组中),这就造成了处理顺序和访问顺序是不一致的。

迭代法写中序遍历,就需要借用指针的遍历来帮助访问节点,栈则用来处理节点上的元素。

var inorderTraversal = function(root) {
  const result = []
  const queue = []
  while (root || queue.length) {
    while (root.left) {
      queue.push(root)
      root = root.left
    }
    root = root.pop()
    result.push(root.val)
    root = root.right
  }
  return result
};

广度优先遍历(BFS)(层次遍历)

上面图层次遍历的结果就是

[	['A'],
	['B', 'C'],
	['D', 'E', 'F', 'G']
]
var levelOrder = function(root) {
  const res = []
  const traversal = (root, depth) => {
    if (root === null) return
    if (!res[depth]) {
      res[depth] = []
    }
    traversal(root.left, depth + 1)
    res[depth].push(root.val)
    traversal(root.right, depth + 1)
  }
  traversal(root, 0)
  return res
}