diff --git "a/problems/\344\272\214\345\217\211\346\240\221\347\232\204\347\273\237\344\270\200\350\277\255\344\273\243\346\263\225.md" "b/problems/\344\272\214\345\217\211\346\240\221\347\232\204\347\273\237\344\270\200\350\277\255\344\273\243\346\263\225.md" index a6d4e3ffc3..25756a9146 100644 --- "a/problems/\344\272\214\345\217\211\346\240\221\347\232\204\347\273\237\344\270\200\350\277\255\344\273\243\346\263\225.md" +++ "b/problems/\344\272\214\345\217\211\346\240\221\347\232\204\347\273\237\344\270\200\350\277\255\344\273\243\346\263\225.md" @@ -227,7 +227,8 @@ public: ## 其他语言版本 ### Java: -迭代法前序遍历代码如下: + +迭代法前序遍历(空指针标记法)代码如下: ```java class Solution { @@ -239,11 +240,10 @@ class Solution { TreeNode node = st.peek(); if (node != null) { st.pop(); // 将该节点弹出,避免重复操作,下面再将右左中节点添加到栈中(前序遍历-中左右,入栈顺序右左中) - if (node.right!=null) st.push(node.right); // 添加右节点(空节点不入栈) - if (node.left!=null) st.push(node.left); // 添加左节点(空节点不入栈) - st.push(node); // 添加中节点 + if (node.right != null) st.push(node.right); // 添加右节点(空节点不入栈) + if (node.left != null) st.push(node.left); // 添加左节点(空节点不入栈) + st.push(node); // 添加中节点 st.push(null); // 中节点访问过,但是还没有处理,加入空节点做为标记。 - } else { // 只有遇到空节点的时候,才将下一个节点放进结果集 st.pop(); // 将空节点弹出 node = st.peek(); // 重新取出栈中元素 @@ -256,34 +256,34 @@ class Solution { } ``` -迭代法中序遍历代码如下: +迭代法中序遍历(空指针标记法)代码如下: ```java class Solution { -public List inorderTraversal(TreeNode root) { + public List inorderTraversal(TreeNode root) { List result = new LinkedList<>(); - Stack st = new Stack<>(); - if (root != null) st.push(root); - while (!st.empty()) { - TreeNode node = st.peek(); - if (node != null) { - st.pop(); // 将该节点弹出,避免重复操作,下面再将右中左节点添加到栈中(中序遍历-左中右,入栈顺序右中左) - if (node.right!=null) st.push(node.right); // 添加右节点(空节点不入栈) - st.push(node); // 添加中节点 - st.push(null); // 中节点访问过,但是还没有处理,加入空节点做为标记。 - if (node.left!=null) st.push(node.left); // 添加左节点(空节点不入栈) - } else { // 只有遇到空节点的时候,才将下一个节点放进结果集 - st.pop(); // 将空节点弹出 - node = st.peek(); // 重新取出栈中元素 - st.pop(); - result.add(node.val); // 加入到结果集 + Stack st = new Stack<>(); + if (root != null) st.push(root); + while (!st.empty()) { + TreeNode node = st.peek(); + if (node != null) { + st.pop(); // 将该节点弹出,避免重复操作,下面再将右中左节点添加到栈中(中序遍历-左中右,入栈顺序右中左) + if (node.right != null) st.push(node.right); // 添加右节点(空节点不入栈) + st.push(node); // 添加中节点 + st.push(null); // 中节点访问过,但是还没有处理,加入空节点做为标记。 + if (node.left != null) st.push(node.left); // 添加左节点(空节点不入栈) + } else { // 只有遇到空节点的时候,才将下一个节点放进结果集 + st.pop(); // 将空节点弹出 + node = st.peek(); // 重新取出栈中元素 + st.pop(); + result.add(node.val); // 加入到结果集 + } } + return result; } - return result; -} } ``` -迭代法后序遍历代码如下: +迭代法后序遍历(空指针标记法)代码如下: ```java class Solution { public List postorderTraversal(TreeNode root) { @@ -294,11 +294,10 @@ class Solution { TreeNode node = st.peek(); if (node != null) { st.pop(); // 将该节点弹出,避免重复操作,下面再将中右左节点添加到栈中(后序遍历-左右中,入栈顺序中右左) - st.push(node); // 添加中节点 + st.push(node); // 添加中节点 st.push(null); // 中节点访问过,但是还没有处理,加入空节点做为标记。 if (node.right!=null) st.push(node.right); // 添加右节点(空节点不入栈) - if (node.left!=null) st.push(node.left); // 添加左节点(空节点不入栈) - + if (node.left!=null) st.push(node.left); // 添加左节点(空节点不入栈) } else { // 只有遇到空节点的时候,才将下一个节点放进结果集 st.pop(); // 将空节点弹出 node = st.peek(); // 重新取出栈中元素 @@ -311,6 +310,150 @@ class Solution { } ``` +迭代法前序遍历(boolean 标记法)代码如下: + +```java +// LeetCode提交时注意添加导包语句 +import java.util.AbstractMap.SimpleEntry; + +class Solution { + public List preorderTraversal(TreeNode root) { + List result = new ArrayList<>(); + if (root == null) + return result; + Stack> stack = new Stack<>(); + stack.push(new SimpleEntry<>(root, false)); + + while (!stack.isEmpty()) { + TreeNode node = stack.peek().getKey(); + // 多加一个visited参数,使“迭代统一写法”成为一件简单的事 + boolean visited = stack.peek().getValue(); + stack.pop(); + + // visited为True,表示该节点和两个儿子位次之前已经安排过了,现在可以收割节点了 + if (visited) { + result.add(node.val); + continue; + } + + // visited当前为false, 表示初次访问本节点,此次访问的目的是“把自己和两个儿子在栈中安排好位次” + + // 前序遍历是'中左右',右儿子最先入栈,最后出栈 + if (node.right != null) { + stack.push(new SimpleEntry<>(node.right, false)); + } + + // 左儿子位置居中 + if (node.left != null) { + stack.push(new SimpleEntry<>(node.left, false)); + } + + // 节点自己最后入栈,最先出栈 + // 同时,设置 visited 为 true,表示下次再访问本节点时,允许收割 + stack.push(new SimpleEntry<>(node, true)); + } + + return result; + } +} +``` + +迭代法中序遍历(boolean 标记法)代码如下: + +```java +// LeetCode提交时注意添加导包语句 +import java.util.AbstractMap.SimpleEntry; + +class Solution { + public List inorderTraversal(TreeNode root) { + List result = new ArrayList<>(); + if (root == null) + return result; + Stack> stack = new Stack<>(); + stack.push(new SimpleEntry<>(root, false)); + + while (!stack.isEmpty()) { + TreeNode node = stack.peek().getKey(); + // 多加一个visited参数,使“迭代统一写法”成为一件简单的事 + boolean visited = stack.peek().getValue(); + stack.pop(); + + // visited为True,表示该节点和两个儿子位次之前已经安排过了,现在可以收割节点了 + if (visited) { + result.add(node.val); + continue; + } + + // visited当前为false, 表示初次访问本节点,此次访问的目的是“把自己和两个儿子在栈中安排好位次” + + // 中序遍历是'左中右',右儿子最先入栈,最后出栈 + if (node.right != null) { + stack.push(new SimpleEntry<>(node.right, false)); + } + + // 把自己加回到栈中,位置居中 + // 同时,设置 visited 为 true,表示下次再访问本节点时,允许收割 + stack.push(new SimpleEntry<>(node, true)); + + // 左儿子最后入栈,最先出栈 + if (node.left != null) { + stack.push(new SimpleEntry<>(node.left, false)); + } + } + + return result; + } +} +``` + +迭代法后序遍历(boolean 标记法)代码如下: + +```java +// LeetCode提交时注意添加导包语句 +import java.util.AbstractMap.SimpleEntry; + +class Solution { + public List postorderTraversal(TreeNode root) { + List result = new ArrayList<>(); + if (root == null) + return result; + Stack> stack = new Stack<>(); + stack.push(new SimpleEntry<>(root, false)); + + while (!stack.isEmpty()) { + TreeNode node = stack.peek().getKey(); + // 多加一个visited参数,使“迭代统一写法”成为一件简单的事 + boolean visited = stack.peek().getValue(); + stack.pop(); + + // visited为True,表示该节点和两个儿子位次之前已经安排过了,现在可以收割节点了 + if (visited) { + result.add(node.val); + continue; + } + + // visited当前为false, 表示初次访问本节点,此次访问的目的是“把自己和两个儿子在栈中安排好位次” + + // 后序遍历是'左右中',节点自己最先入栈,最后出栈 + // 同时,设置 visited 为 true,表示下次再访问本节点时,允许收割 + stack.push(new SimpleEntry<>(node, true)); + + // 右儿子位置居中 + if (node.right != null) { + stack.push(new SimpleEntry<>(node.right, false)); + } + + // 左儿子最后入栈,最先出栈 + if (node.left != null) { + stack.push(new SimpleEntry<>(node.left, false)); + } + } + + return result; + } +} +``` + ### Python: > 迭代法前序遍历(空指针标记法):