数据结构 --- 二叉树的遍历
二叉树的遍历
递归实现 先序 中序 后序遍历
递归的实现很简答,并且前中后共用一个模版。
先序遍历
var preorderTraversal = function(root) {
let res = []
if(root === null) return res
function helper(root){
if(root === null) return
res.push(root.val)
if(root.left) helper(root.left)
if(root.right) helper(root.right)
}
helper(root)
return res
};
中序遍历
顺序为:左 中 右
var inorderTraversal = function(root) {
let res = []
if(root === null) return res
function helper(root){
if(root === null) return
if(root.left) helper(root.left) //这两行交换了顺序
res.push(root.val) //这两行交换了顺序
if(root.right) helper(root.right)
}
helper(root)
return res
};
后序遍历
顺序为:左 右 中
var inorderTraversal = function(root) {
let res = []
if(root === null) return res
function helper(root){
if(root === null) return
if(root.left) helper(root.left)
if(root.right) helper(root.right)
res.push(root.val)
}
helper(root)
return res
};
递归三部曲
- 规定参数和返回值
- 确定终止条件
- 确定单层递归的逻辑
二叉树的迭代遍历
我们都知道,递归虽代码量小,但不是一种很高效的解决问题的办法,严格的面试官有可能考验你使用迭代遍历二叉树问题。
迭代实现二叉树的遍历的精髓在于标记每个根节点(栈后面补一个null)这样就可以知道这个根节点有没有添加它的左右节点进栈,当发现被标记过的节点,把它放进结果数组即可。
先序遍历
var preorderTraversal = function(root) {
let stack = []
let res = []
if(root === null) return res
stack.push(root)
while(stack.length){
let node = stack.pop()
if(node === null){
res.push(stack.pop().val) //是被标记过的节点,直接加入res
continue
}
else { //不是,把它的左右节点入栈,并把它自己标记入栈
node.right && stack.push(node.right) //入栈顺序与结果是相反的
node.left && stack.push(node.left)
stack.push(node)
stack.push(null)
}
}
return res
};
中序遍历
var inorderTraversal = function(root) {
let stack = []
let res = []
if(root === null) return res
stack.push(root)
while(stack.length){
let node = stack.pop()
if(node === null){
res.push(stack.pop().val) //是被标记过的节点,直接加入res
continue
}
else { //不是,把它的左右节点入栈,并把它自己标记入栈
node.right && stack.push(node.right) //入栈顺序与结果是相反的
stack.push(node)
stack.push(null)
node.left && stack.push(node.left)
}
}
return res
};
后序遍历
var inorderTraversal = function(root) {
let stack = []
let res = []
if(root === null) return res
stack.push(root)
while(stack.length){
let node = stack.pop()
if(node === null){
res.push(stack.pop().val) //是被标记过的节点,直接加入res
continue
}
else { //不是,把它的左右节点入栈,并把它自己标记入栈
stack.push(node)
stack.push(null)
node.right && stack.push(node.right) //入栈顺序与结果是相反的
node.left && stack.push(node.left)
}
}
return res
};
二叉树的层次遍历
学会二叉树的层序遍历,可以一口气打完以下十题,10分钟leetcode刷题数+10(不是:
- 102.二叉树的层序遍历
- 107.二叉树的层次遍历II
- 199.二叉树的右视图
- 637.二叉树的层平均值
- 429.N叉树的层序遍历
- 515.在每个树行中找最大值
- 116.填充每个节点的下一个右侧节点指针
- 117.填充每个节点的下一个右侧节点指针II
- 104.二叉树的最大深度
- 111.二叉树的最小深度
根据上面迭代的算法,我们其实可以想到,层次遍历不就是先输出左右节点,把左右节点的左右节点入队不就行了么,用一个队列即可实现啊
var levelOrder = function(root) {
let queue = []
let res = []
if(root === null) return res
queue.push(root)
while(queue.length){
let len = queue.length
let curRes = [] //每一层的节点
for(let i=0;i<len;i++){
let node = queue.shift()
curRes.push(node.val)
node.left && queue.push(node.left)
node.right && queue.push(node.right)
}
res.push(curRes)
}
return res
};