层序遍历
层序遍历一个二叉树。就是从左到右一层一层的去遍历二叉树。这种遍历的方式和我们之前讲过的都不太一样。
需要借用一个辅助数据结构即队列来实现,队列先进先出,符合一层一层遍历的逻辑,而用栈先进后出适合模拟深度优先遍历也就是递归的逻辑。
而这种层序遍历方式就是图论中的广度优先遍历,只不过我们应用在二叉树上。动画:
226.翻转二叉树 (优先掌握递归)
思路:
遍历的过程中去翻转每一个节点的左右孩子就可以达到整体翻转的效果。
注意只要把每一个节点的左右孩子翻转一下,就可以达到整体翻转的效果
这道题目使用前序遍历和后序遍历都可以,唯独中序遍历不方便,因为中序遍历会把某些节点的左右孩子翻转了两次
代码实现
//使用递归版本的前序遍历
var invertTree = function (root) {
if (!root) {
return root
}
let rightNode = root.right
root.right = invertTree(root.left)
root.left = invertTree(rightNode)
return root
}
//使用迭代版本(统一模板))的前序遍历:
var invertTree = function (root) {
const invertNode = function (root, left, right) {
let temp = left
left = right
right = temp
root.left = left
root.right = right
}
const stack = [];
if (root === null) {
return root
}
stack.push(root)
while (stack.length) {
let node = stack.pop()
if (node !== null) {
node.right && stack.push(node.right)
node.left && stack.push(node.left)
stack.push(node)
stack.push(null)
} else {
node = stack.pop()
invertNode(node, node.left, node.right)
}
}
return root
}
//使用层序遍历
var invertTree = function (root) {
const invertNode = function (root, left, right) {
let temp = left
left = right
right = temp
root.left = left
root.right = right
}
let queue = []
queue.push(root)
if (root === null) {
return root
}
while (queue.length !== 0) {
let length = queue.length
for (let i = 0; i < length; i++) {
let node = queue.shift()
invertNode(node, node.left, node.right)
node.left && queue.push(node.left)
node.right && queue.push(node.right)
}
}
return root
}
101. 对称二叉树 (优先掌握递归)
思路:
首先想清楚,判断对称二叉树要比较的是哪两个节点,要比较的可不是左右节点!
对于二叉树是否对称,要比较的是根节点的左子树与右子树是不是相互翻转的,理解这一点就知道了其实我们要比较的是两个树(这两个树是根节点的左右子树),所以在递归遍历的过程中,也是要同时遍历两棵树。
是因为要遍历两棵树而且要比较内侧和外侧节点,所以准确的来说是一个树的遍历顺序是左右中,一个树的遍历顺序是右左中。
但都可以理解算是后序遍历,尽管已经不是严格上在一个树上进行遍历的后序遍历了。
代码实现
//递归
var compare = function (left, right) {
if (root === null) {
return true
}
if (left == null && right !== null) { return false } else if (left !== null && right == null) {
return false
} else if (left == null && right == null) {
return true
} else if (left.val !== right.val) {
return false
}
let outSide = compare(left.left, right.right)
let inSide = compare(left.right, right.left)
let isSame = outSide && inSide
return isSame
};
var isSymmetric = function (root) {
if (root === null) {
return true
}
return compare(root.left, root.right)
}
//迭代
var isSymmetric = function (root) {
if (root === null) {
return true
}
let queue = []
queue.push(root.left);
queue.push(root.right)
while (!queue.length) {
let leftNode = queue.shift()
let rightNode = queue.shift()
if (!leftNode && !rightNode) {
continue
}
if (!leftNode || !rightNode || leftNode.val !== rightNode.val) {
return false
}
queue.push(leftNode.left)
queue.push(rightNode.right)
queue.push(leftNode.right)
queue.push(rightNode.left)
}
return true
}
//栈实现迭代
var isSymmetric = function (root) {
if (root === null) {
return true
}
let stack = []
stack.push(root.left);
stack.push(root.right)
while (stack.length) {
let rightNode = stack.pop()
let leftNode = stack.pop()
if (!leftNode && !rightNode) {
continue
}
if (!leftNode || !rightNode || leftNode.val !== rightNode.val) {
return false
}
stack.push(leftNode.left)
stack.push(rightNode.right)
stack.push(leftNode.right)
stack.push(rightNode.left)
}
return true
}
总结:
不管是迭代还是递归 都是需要掌握的 早日形成自己的解题习惯是最重要的 加油~~