树的遍历方式:
1、广度优先 层次 采用迭代法。
2、深度优先 前序,中序,后序,指的是根节点的顺序 采用 递归,迭代实现。
递归三要素:
1、参数,返回值
2、终止条件
3、每一次递归逻辑
递归实现
前序,中序,后序类似,这里只展示后续实现。
/**
* 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> postorderTraversal(TreeNode root) {
List<Integer> list = new ArrayList();
digui(root,list);
return list;
}
public void digui(TreeNode r ,List<Integer> list){
if(r == null) return ;
//左右中
digui(r.left,list);
digui(r.right,list);
list.add(r.val);
}
}
迭代法
迭代,用栈实现。
要输出的元素出栈,遍历的元素压栈。
迭代法实现
前序实现
先压右节点,再压左节点,确保输出顺序先左后右。
注意注意:空指针不需要压栈。
/**
* 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> list = new ArrayList<>();
//迭代法
if(root == null) return list;
Stack<TreeNode> stack = new Stack();
stack.push(root);
while(!stack.isEmpty()){
TreeNode t = stack.pop();
list.add(t.val);
if(t.right != null) stack.push(t.right);
if(t.left != null) stack.push(t.left);
}
return list;
}
}
小提示:
注意边界值为空的处理。
中序实现
先遍历左节点,压栈。
没有左节点了,出栈,输出。
再遍历右节点,压栈。
class Solution {
public List<Integer> inorderTraversal(TreeNode root) {
//中序排列 左 中 右
List<Integer> list = new ArrayList<>();
TreeNode cur = root;
Stack<TreeNode> stack = new Stack<>();
if(root == null) return list;
while(!stack.isEmpty() || cur!=null){
if(cur!=null){
stack.push(cur);
cur = cur.left;
}else{
cur = stack.pop();
list.add(cur.val);
cur = cur.right;
}
}
return list;
}
}
后序实现
前序 中左右 后序 左右中
先实现 中右左,然后反转,实现左右中。
class Solution {
public List<Integer> postorderTraversal(TreeNode root) {
//中,右,左
List<Integer> list = new ArrayList<>();
Stack<TreeNode> stack = new Stack<>();
if(root == null) return list;
stack.push(root);
while(!stack.isEmpty()){
TreeNode r = stack.pop();
list.add(r.val);
if(r.left != null) stack.push(r.left);
if(r.right != null) stack.push(r.right);
}
Collections.reverse(list);
return list;
}
}
统一迭代法的实现
前文不统一的原因:
访问顺序,跟遍历返回结果的顺序不一致。
解决:如果是要遍历结果的元素,栈后面跟一个空指针来辨别。
前序遍历实现如下,中序遍历,后序遍历,只需微调顺序。
前序遍历:中左右。 存入栈顺序:右,左,中(处理元素,后面跟 null 标识)
中序遍历:左中右。存入栈顺序:右,中(后跟 null 标识),左
后序遍历:左右中。存入顺序:中(后跟 null 标识),右,左
class Solution {
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> list = new ArrayList<>();
if(root == null) return list;
Stack<TreeNode> stack = new Stack<>();
stack.push(root);
while(!stack.isEmpty()){
TreeNode t = stack.peek();
if(t == null){
stack.pop();
list.add(stack.pop().val);
}else{
stack.pop();
if(t.right != null) stack.push(t.right);
if(t.left != null) stack.push(t.left);
stack.push(t);
stack.push(null);
}
}
return list;
}
}
注意容易出错的地方:
1、获取栈顶元素的方法:peek()
2、切记每个遍历节点,先出栈,再入栈。不要只入不出,运行超出预期。