【README】
本文复习了通过java迭代实现 二叉树先序,中序,后序遍历;
本文引入了 栈,替换了递归,对二叉树进行遍历;
补充:使用递归遍历二叉树缺点:
- 众所周知,每次递归,实际是把方法调用帧,连同方法参数一起压入到方法栈; jvm中的方法栈的深度有限,一旦二叉树节点个数过多,可能导致栈溢出的情况;
- 我们通过压入显式栈,替换了递归,即替换了方法栈;在可能的情况下,即便二叉树节点过多,也不会报栈溢出异常;
- 显式栈,可以用 数组来实现,不一定是 Stack类;
【1】二叉树遍历
【1.1】先序遍历
1)遍历规则
- 对于一颗二叉树,先遍历其根节点,再遍历左孩子,最后遍历右孩子;
- 若左孩子下面挂了一棵树(左子树),则继续遍历左子树;
- 若右孩子下面一棵树(右子树),则继续遍历右子树;
2)先序遍历迭代实现:
/**
* @description 先序遍历
* @author xiao tang
* @date 2022/11/20
*/
public static void printByPreOrder(MyBinTree root) {
Stack<MyBinTree> stack = new Stack<>();
stack.push(root);
while(!stack.isEmpty()) {
root = stack.pop();
if (root == null) {
System.out.print("NULL ");
} else {
System.out.print(root.value + " ");
stack.push(root.right);
stack.push(root.left);
}
}
}
// 二叉树
public class MyBinTree {
int value;
MyBinTree left;
MyBinTree right;
public MyBinTree(int value) {
this.value = value ;
}
}
【1.2】中序遍历
1)遍历规则
- 对于一颗二叉树,先遍历左孩子,再遍历根节点,最后遍历右孩子;
- 若左孩子下面挂了一棵树(左子树),则继续遍历左子树;
- 若右孩子下面一棵树(右子树),则继续遍历右子树;
2)中序遍历迭代实现:
/**
* @description 中序遍历
* @author xiao tang
* @date 2022/11/20
*/
public static void printByInOrder(MyBinTree root) {
Stack<MyBinTree> stack = new Stack<>();
stack.push(root);
while(!stack.isEmpty()) {
if (root != null) {
stack.push(root.left);
root = root.left;
} else {
// 左儿子或右儿子为空
stack.pop();
System.out.print("NULL ");
if (!stack.isEmpty()) {
root = stack.pop();
System.out.print(root.value + " ");
stack.push(root.right);
root = root.right;
}
}
}
}
【1.3】后序遍历
1)遍历规则
- 对于一颗二叉树,先遍历左孩子,再遍历右孩子,最后遍历根节点;
- 若左孩子下面挂了一棵树(左子树),则继续遍历左子树;
- 若右孩子下面一棵树(右子树),则继续遍历右子树;
2)后序遍历迭代实现:
/**
* @description 后序遍历
* @author xiao tang
* @date 2022/11/20
*/
public static void printByPostOrder(MyBinTree root) {
Stack<MyBinTree> stack = new Stack<>();
stack.push(root);
// 空的右孩子哨兵, 空的左孩子哨兵为null, 以把空右孩子 与 空左孩子 区别开
MyBinTree rightNullNode = new MyBinTree(0);
while(!stack.isEmpty()) {
if (root != null && root != rightNullNode) {
stack.push(root.left);
root = root.left;
} else {
// 左孩子或右孩子为null
MyBinTree lastNodeVisited = stack.pop();
System.out.print("NULL ");
while (!stack.isEmpty()) {
root = stack.peek();
MyBinTree rightChild = root.right != null ? root.right : rightNullNode;
if (rightChild == lastNodeVisited) {
// 若刚刚访问的节点 等于 右孩子,则根节点弹出
lastNodeVisited = stack.pop();
System.out.print(lastNodeVisited.value + " ");
} else {
stack.push(rightChild);
root = rightChild;
break;
}
}
}
}
}
【2】测试案例
1)二叉树结构
2)测试案例代码:
public static void main(String[] args) {
MyBinTree head = new MyBinTree(1);
head.left = new MyBinTree(2);
head.right = new MyBinTree(3);
head.left.left = new MyBinTree(4);
head.left.right = new MyBinTree(5);
head.right.left = new MyBinTree(6);
head.right.right = new MyBinTree(7);
head.left.left.left = new MyBinTree(8);
head.left.right.right = new MyBinTree(9);
// 先序打印
printByPreOrder(head);
System.out.println();
// 中序打印
printByInOrder(head);
System.out.println();
// 后序打印
printByPostOrder(head);
}
3)打印结果:
先序遍历:1 2 4 8 NULL NULL NULL 5 NULL 9 NULL NULL 3 6 NULL NULL 7 NULL NULL
中序遍历:NULL 8 NULL 4 NULL 2 NULL 5 NULL 9 NULL 1 NULL 6 NULL 3 NULL 7 NULL
后序遍历:NULL NULL 8 NULL 4 NULL NULL NULL 9 5 2 NULL NULL 6 NULL NULL 7 3 1