public class TreeTraversal {
public void preOrder(TreeNode root){
// 先序递归
if (root == null){
return;
}
// 根左右 每个节点都访问三次
System.out.println("root.val = " + root.val);
preOrder(root.left);
preOrder(root.right);
}
/**
* 先序遍历非递归写法
* @param root
*/
public void preOrderWithoutRecursive(TreeNode root){
// 问题1 : 忘记校验root
if (root == null){
return;
}
// 思路 递归本质是栈,借助栈来实现非递归的先序遍历
LinkedList<TreeNode> stack = new LinkedList<>();
// 根节点入栈,栈不空就继续遍历
stack.add(root);
while (!stack.isEmpty()){
// 由于先序,直接出栈并打印
TreeNode popNode = stack.pop();
// 先序遍历
System.out.println("popNode.val = " + popNode.val);
// 子节点入栈,继续遍历,不断的根 左 右
// 栈结构逆反所以 右 左 入栈
// 问题2:忘记校验左右非空 牢记参数校验
if (popNode.right!= null){
stack.push(popNode.right);
}
// 左侧节点永远比右侧先出栈被遍历到
if (popNode.left!= null){
stack.push(popNode.left);
}
}
}
/**
* 中序遍历
* @param root
*/
public void inOrder(TreeNode root){
// 递归
if (root == null){
return;
}
// 左根右 每个节点都访问三次
inOrder(root.left);
// 中序就是在第二次访问到自身时输出/做事
System.out.println("root.val = " + root.val);
inOrder(root.right);
}
/**
* 中序遍历非递归写法
* @param root
*/
public void inOrderWithoutRecursive(TreeNode root){
// 问题1 : 忘记校验root
if (root == null){
return;
}
// 思路 递归本质是栈,借助栈来实现非递归的中序遍历
LinkedList<TreeNode> stack = new LinkedList<>();
// 根节点入栈,栈不空就继续遍历
stack.add(root);
while (!stack.isEmpty()){
// 如果遍历左侧非空则一直入栈
if(root.left != null){
stack.push(root.left);
root = root.left;
}else{
// 遍历到左侧底部,由于一层循环
// 直接出栈并访问
TreeNode popNode = stack.pop();
System.out.println(popNode.val);
// 判断是否需要访问右侧
if(popNode.right != null){
root = popNode.right;
stack.push(popNode.right);
}
}
}
}
/**
* 中序遍历非递归写法
* @param root
*/
public void inOrderWithoutRecursive1(TreeNode root){
// 问题1 : 忘记校验root
if (root == null){
return;
}
// 思路 递归本质是栈,借助栈来实现非递归的中序遍历
LinkedList<TreeNode> stack = new LinkedList<>();
// 优化 直接遍历 更加符合语义
while (root != null || !stack.isEmpty()){
// 如果遍历左侧非空则一直入栈
if(root != null){
// 直接放入而不是左侧了
stack.push(root);
root = root.left;
}else{
// 遍历到左侧底部,由于一层循环
// 直接出栈并访问
TreeNode popNode = stack.pop();
System.out.println(popNode.val);
// 优化 直接访问右侧
root = popNode.right;
}
}
}
/**
* 后序遍历
* @param root
*/
public void postOrder(TreeNode root){
// 递归
if (root == null){
return;
}
// 左右根 每个节点都访问三次
postOrder(root.left);
postOrder(root.right);
// 后序就是在第三次访问到自身时输出/做事
System.out.println("root.val = " + root.val);
}
/**
* 后序遍历非递归写法
* @param root
*/
public void postOrderWithoutRecursive(TreeNode root){
// 问题1 : 忘记校验root
if (root == null){
return;
}
// 思路 递归本质是栈,借助栈来实现非递归的后序
// 后序与先序做比较 先序 根 左 右 后序 左 右 根
// 后序的逆转 根 右 左
// 先序非递归是右左入栈所以出栈是左右,后序只要左右入栈出栈就是右左,后序就是先序的逆反+栈输出,出栈入辅助后逆序输出
LinkedList<TreeNode> stack1 = new LinkedList<>();
LinkedList<TreeNode> stack2 = new LinkedList<>();
// 根节点入栈
stack1.push(root);
while (!stack1.isEmpty()){
// 先序是先输出,后序直接入栈 并且由于出栈特性,每个节点都只访问一次 不会出现重复入栈的动作
TreeNode popNode = stack1.pop();
stack2.push(popNode);
// 左右遍历即可
if (popNode.left != null){
stack1.push(popNode.left);
}
if (popNode.right != null){
stack1.push(popNode.right);
}
}
while (!stack2.isEmpty()){
// 错误 应该直接访问stack2
// System.out.println("stack1.pop().val = " + stack1.pop().val);
System.out.println("stack2.pop().val = " + stack2.pop().val);
}
}
}
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;
}
}
java前中后 遍历 递归与非递归
最新推荐文章于 2022-06-16 12:16:37 发布