[LeetCode] 144. 二叉树的前序遍历
[LeetCode] 145. 二叉树的后序遍历[LeetCode] 94. 二叉树的中序遍历
二叉树理论基础数据结构的定义:
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
自己看到题目的第一想法
经典的数据结构题目, 似曾相似又极其陌生. 乍一眼感觉都会, 做起题来完全崩溃... 废了废了...
看完代码随想录之后的想法
看完二叉树的理论篇之后, 对二叉树庞大的只是结构还是产生了一定的恐惧. 如果说曾经以为前中后序遍历二叉树是基础入门, 现在只能说, 遍历二叉树不过是入门前的热身...
满二叉树、完全二叉树、搜索二叉树、平衡二叉树、对称二叉树、二叉树的深度、合并二叉树、二叉树的公共祖先... 看到这些概念头都大了.
递归遍历二叉树算是比较容易的部分了, 因为前中后三种顺序遍历的逻辑都差不多.
// 前序遍历
class Solution {
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> result = new ArrayList<>();
if (root == null) {
return result;
}
preorderTraversalRecursion(root, result);
return result;
}
private void preorderTraversalRecursion(TreeNode node, List<Integer> result) {
if (node == null || result == null) {
return;
}
result.add(node.val);
if (node.left != null) {
preorderTraversalRecursion(node.left, result);
}
if (node.right != null) {
preorderTraversalRecursion(node.right, result);
}
}
}
// 后序遍历
class Solution {
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> result = new ArrayList<>();
if (root == null) {
return result;
}
postorderTraversalRecursion(root, result);
return result;
}
private void postorderTraversalRecursion(TreeNode node, List<Integer> result) {
if (node == null || result == null) {
return;
}
if (node.left != null) {
postorderTraversalRecursion(node.left, result);
}
if (node.right != null) {
postorderTraversalRecursion(node.right, result);
}
result.add(node.val);
}
}
// 中序遍历
class Solution {
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> result = new ArrayList<>();
if (root == null) {
return result;
}
inorderTraversalRecursion(root, result);
return result;
}
private void inorderTraversalRecursion(TreeNode node, List<Integer> result) {
if (node == null || result == null) {
return;
}
if (node.left != null) {
inorderTraversalRecursion(node.left, result);
}
result.add(node.val);
if (node.right != null) {
inorderTraversalRecursion(node.right, result);
}
}
}
// 迭代法前序遍历
class Solution {
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> result = new ArrayList<>();
if (root == null) {
return result;
}
Stack<TreeNode> nodes = new Stack<>();
TreeNode node = null;
nodes.push(root);
while (!nodes.isEmpty()) {
node = nodes.pop();
result.add(node.val);
if (node.right != null) {
nodes.push(node.right);
}
if (node.left != null) {
nodes.push(node.left);
}
}
return result;
}
}
// 迭代法后序遍历. (左右中 =》中右左)
// 迭代法后续遍历比较特殊, 因为只有先遍历中间节点的时候, 才能通过栈的结构写出简洁的代码
// 然而后续遍历的顺序是: 左 右 中, 当我们把后续遍历的顺序逆向一下, 可以得到 中 右 左
// 因此我们按照 中 右 左 的顺序遍历之后, 将最后列表中的结果反转一下, 就得到我们想要的结果了
// 自己在编码的时候总是想不起来后续遍历是需要通过转换遍历顺序这个逻辑.
// 一定要记住只有在遍历过的节点中, 优先处理中间节点的时候, 处理顺序才能和遍历顺序一致.
// 才能得到简单清爽的实现方案.
class Solution {
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> result = new ArrayList<>();
if (root == null) {
return result;
}
Stack<TreeNode> nodes = new Stack<>();
TreeNode node = null;
nodes.push(root);
while (!nodes.isEmpty()) {
node = nodes.pop();
result.add(node.val);
if (node.left != null) {
nodes.push(node.left);
}
if (node.right != null) {
nodes.push(node.right);
}
}
int temp = 0;
// 总是会忘记反转.
for (int i = 0; i < result.size()/2; i++) {
temp = result.get(i);
result.set(i, result.get(result.size() - 1 -i));
result.set(result.size() - 1 - i, temp);
}
return result;
}
}
// 迭代法的中序遍历
// 这里突然卡壳了... 因为不知道怎么处理右节点...
// 然后突然又想通了:
// 当一个节点没有左节点时, 可以认为它的左节点已经处理完成.
// 这时候把当前节点加入到结果中. 同时需要处理它的右节点, 因此把右节点添加到栈中.
class Solution {
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> result = new ArrayList<>();
if (root == null) {
return result;
}
Stack<TreeNode> nodes = new Stack<>();
TreeNode node = root;// 这里 node 表示 root 节点.
while (node != null || !nodes.isEmpty()) {
if (node != null) {
nodes.push(node);
node = node.left; // 左
} else {
node = nodes.pop();
result.add(node.val);// 中
node = node.right; // 右
}
}
return result;
}
}
// 统一风格法前序遍历
class Solution {
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> result = new ArrayList<>();
if (root == null) {
return result;
}
Stack<TreeNode> nodes = new Stack<>();
TreeNode node = null;
nodes.push(root);
while (!nodes.isEmpty()) {
node = nodes.pop();
if (node != null) {
if (node.right != null) {
nodes.push(node.right);
}
if (node.left != null) {
nodes.push(node.left);
}
nodes.push(node);
nodes.push(null);
} else {
node = nodes.pop();
result.add(node.val);
}
}
return result;
}
}
// 统一风格法后序遍历
class Solution {
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> result = new ArrayList<>();
if (root == null) {
return result;
}
Stack<TreeNode> nodes = new Stack<>();
TreeNode node = null;
nodes.push(root);
while (!nodes.isEmpty()) {
node = nodes.pop();
if (node != null) {
nodes.push(node);
nodes.push(null);
if (node.right != null) {
nodes.push(node.right);
}
if (node.left != null) {
nodes.push(node.left);
}
} else {
node = nodes.pop();
result.add(node.val);
}
}
return result;
}
}
// 统一风格中序遍历
class Solution {
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> result = new ArrayList<>();
if (root == null) {
return result;
}
Stack<TreeNode> nodes = new Stack<>();
TreeNode node = null;
nodes.push(root);
while (!nodes.isEmpty()) {
node = nodes.pop();
if (node != null) {
if (node.right != null) {
nodes.push(node.right);
}
nodes.push(node);
nodes.push(null);
if (node.left != null) {
nodes.push(node.left);
}
} else {
node = nodes.pop();
result.add(node.val);
}
}
return result;
}
}
自己实现过程中遇到哪些困难
特别是迭代法的中序遍历, 突然就卡壳了, 不知道右节点改如何处理, 不小心还造成了死循环. 解决了之后重新看了一下文章, 发现示例代码中会明确的标出哪部分是处理左节点, 哪部分是处理右节点(对应递归三步心法就是, 关注单次的处理逻辑).
在处理统一风格的遍历方法时, 也会不小心的在前序遍历时, 没有添加 null 标记, 但是这部分可以快速的识别出来.
// 默写一遍
class Solution {
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> result = new ArrayList<>();
if (root == null) {
return result;
}
Stack<TreeNode> nodes = new Stack<>();
TreeNode node = root;
while (node != null || !nodes.isEmpty()) {
if (node != null) {
nodes.push(node);
node = node.left;
} else {
node = nodes.pop();
result.add(node.val);
node = node.right;
}
}
return result;
}
}