前序遍历与后序遍历非递归实现思路:
前序遍历的顺序是:根——左——右。
后序遍历的顺序是:左——右——根。
从上面可以看出,两者的差异仅仅是根的位置一个在最前面,一个在最后面。而遍历函数的传入参数是根(这点及其重要,也解释了为何后面前序后序遍历有些实现是近似的)。
现在封装一个LinkedList:a存储最终的输出顺序。封装另一个LinkedList:b存储要被处理的节点。
传入的是根,由于两种顺序根的位置固定,故从根就可以开始处理。
重点:制定方案,决定从b的哪端开始处理节点,从a的哪端开始插入节点值。之后一直保持这个顺序即可。
如:前序遍历根在最前面,a端最先插入的值是根值,故之后应从尾部插入
后序遍历根在最后面,a端最先插入的值是根值,故之后应从头部插入
举例前序遍历:
b: 根
a:空
b: 根从尾部弹出,压入右、左
a:从尾部添加弹出节点值
反复即可
题目描述
145. Binary Tree Postorder Traversal
Given a binary tree, return the postorder traversal of its nodes' values.
Example:
Input:[1,null,2,3]
1 \ 2 / 3 Output:[3,2,1]
class Solution {
public List<Integer> postorderTraversal(TreeNode root) {
LinkedList<TreeNode> stack = new LinkedList<>();
LinkedList<Integer> output = new LinkedList<>();
if (root == null) {
return output;
}
stack.add(root);
while (!stack.isEmpty()) {
TreeNode node = stack.pollLast();
output.addFirst(node.val);
if (node.left != null) {
stack.add(node.left);
}
if (node.right != null) {
stack.add(node.right);
}
}
return output;
}
}
590. N-ary Tree Postorder Traversal
Given an n-ary tree, return the postorder traversal of its nodes' values.
For example, given a 3-ary
tree:
Return its postorder traversal as: [5,6,3,2,4,1]
.
class Solution { public List<Integer> postorder(Node root) { LinkedList<Node> stack= new LinkedList<>(); LinkedList<Integer> output= new LinkedList<>(); if(root==null) return output; stack.add(root); while(!stack.isEmpty()){ Node tmp= stack.pollLast(); output.addFirst(tmp.val); for(Node n: tmp.children){ if(n!=null) stack.add(n); } } return output; } }
145与590两道题只有树节点的构造稍微不同,实现原理都是相同的。要求不用递归,迭代做、
下图是solution解释中的图,非原创
通过上图可发现:
BFS:从上至下,从左至右
DFS:左右根有三种排列方式
144. Binary Tree Preorder Traversal
Given a binary tree, return the preorder traversal of its nodes' values.
Example:
Input:[1,null,2,3]
1 \ 2 / 3 Output:[1,2,3]
class Solution {
public List<Integer> preorderTraversal(TreeNode root) {
LinkedList<TreeNode> stack= new LinkedList<>();
LinkedList<Integer> output= new LinkedList<>();
if(root==null)
return output;
stack.add(root);
while(!stack.isEmpty()){
TreeNode tmp= stack.pollLast();
output.addLast(tmp.val);
if(tmp.right!=null){
stack.addLast(tmp.right);
}
if(tmp.left!=null){
stack.addLast(tmp.left);
}
}
return output;
}
}
589. N-ary Tree Preorder Traversal
Given an n-ary tree, return the preorder traversal of its nodes' values.
For example, given a 3-ary
tree:
Return its preorder traversal as: [1,3,5,6,2,4]
.
class Solution {
public List<Integer> preorder(Node root) {
LinkedList<Node> stack= new LinkedList<>();
LinkedList<Integer> output= new LinkedList<>();
if(root==null)
return output;
stack.add(root);
while(!stack.isEmpty()){
Node tmp= stack.pollLast();
output.addLast(tmp.val);
int index= tmp.children.size()-1;
for(;index>=0;index--){
Node chil= tmp.children.get(index);
if(chil!=null) stack.addLast(chil);
}
}
return output;
}
}
94. Binary Tree Inorder Traversal
Given a binary tree, return the inorder traversal of its nodes' values.
Example:
Input: [1,null,2,3]
1
\
2
/
3
Output: [1,3,2]
class Solution {
public List<Integer> inorderTraversal(TreeNode root) {
LinkedList<TreeNode> stack= new LinkedList<>();
LinkedList<Integer> output= new LinkedList<>();
if(root==null)
return output;
stack.add(root);
//cur表示下一个可能被处理的节点,对于根而言,是左孩子
TreeNode cur= root.left;
while(cur!=null || !stack.isEmpty()){
//对于每一个可能被处理的节点,要先处理他们的左孩子
while(cur!=null){
stack.addLast(cur);
cur= cur.left;
}
cur= stack.pollLast();
output.addLast(cur.val);
//根已经输出,下一个可能的被处理节点是右孩子
cur= cur.right;
}
return output;
}
}
下面这种中序遍历的方式是错误的,虽然逻辑上乍一看没有什么问题!!!!!如果一定要这么写,一定要判重,有没有加入过它的左孩子
public List<Integer> inorderTraversal(TreeNode root) {
//一种常见的错误写法,peek顶端查看有无左孩子,有的话就加入
//漏洞:可能循环压入多次左孩子导致超时
LinkedList<TreeNode> stack= new LinkedList<>();
LinkedList<Integer> output= new LinkedList<>();
if(root==null)
return output;
stack.add(root);
TreeNode cur= root.left;
while(cur!=null || !stack.isEmpty()){
while(cur!=null){
stack.addLast(cur);
cur= cur.left;
}
cur= stack.pollLast();
output.addLast(cur.val);
cur= cur.right;
}
return output;
}