二叉树的遍历
本文分别介绍了二叉树的四类遍历情况,分别为前序遍历,中序遍历,后序遍历,层次遍历。
分析:
-
递归方式前中后序遍历二叉树:递归方式十分简单,代码一看就懂。
-
非递归方式实现前中后遍历二叉树:
2.1. 前序(根左右)
2.2. 中序(左根右)
2.3. 后序(左右根)
import java.util.LinkedList;
import java.util.Queue;
import java.util.Stack;
public class BinTree {
// 内部类,定义二叉树的结点
class TreeNode{
public String val;
public TreeNode left;
public TreeNode right;
// 构造函数,创建一个结点。
public TreeNode(String val) {
this.val = val;
this.left = null;
this.right = null;
}
}
/**
* 简易创建一个二叉树
* A
* B C
* D E F G
* H I
* J
* @return
*/
public TreeNode creat(){
TreeNode root = new TreeNode("A");
TreeNode node2 = new TreeNode("B");
TreeNode node3 = new TreeNode("C");
TreeNode node4 = new TreeNode("D");
TreeNode node5 = new TreeNode("E");
TreeNode node6 = new TreeNode("F");
TreeNode node7 = new TreeNode("G");
TreeNode node8 = new TreeNode("H");
TreeNode node9 = new TreeNode("I");
TreeNode node10 = new TreeNode("J");
root.left = node2;
root.right = node3;
node2.left = node4;
node2.right = node5;
node3.left = node6;
node3.right = node7;
node5.left = node8;
node6.right = node9;
node9.left = node10;
return root;
}
// 前序递归遍历二叉树--> 根左右的顺序
public void preOrder(TreeNode node){
// 如果所给当前结点为空,直接退出。
if (node==null){
return;
}
// 访问当前结点
System.out.print(node.val+" ");
// 递归调用,访问当前结点的左孩子结点
preOrder(node.left);
// 递归调用,访问当前结点的右孩子结点
preOrder(node.right);
}
// 前序非递归遍历二叉树--> 根左右的顺序
// 递归向非递归的转换,一般是需要借助栈这种数据结构。
public void noRecPreOrder(TreeNode node){
// 如果所给当前结点为空,直接退出。
if (node==null){
return;
}
Stack<TreeNode> stack = new Stack<TreeNode>();
// 根结点入栈
stack.push(node);
/**
* 套路总结
* 1. 入栈
* 2. 出栈
* 3. 入栈
* 4. 出栈
* .....
* 很明显,该模型按照1-2两步进行循环,但是编程的时候,针对这样的循环操作,
* 一般将第一步先操作,然后将2,3步作为一个整体进行循环。
*/
while (!stack.isEmpty()){
// 出栈
TreeNode temp = stack.pop();
// 访问当前结点
System.out.print(temp.val+" ");
// 右孩子先入栈,因为要后遍历
if (temp.right!=null){
stack.push(temp.right);
}
// 左孩子后入栈,因为要先遍历
if (temp.left!=null){
stack.push(temp.left);
}
}
}
// 中序递归遍历二叉树--> 左根右的顺序
public void midOrder(TreeNode node){
// 如果所给当前结点为空,直接退出。
if (node==null){
return;
}
// 递归调用,访问当前结点的左孩子结点
midOrder(node.left);
// 访问当前结点
System.out.print(node.val+" ");
// 递归调用,访问当前结点的右孩子结点
midOrder(node.right);
}
// 中序非递归遍历二叉树--> 左根右的顺序
public void noRecMidOrder(TreeNode node){
// 同样是需要利用栈
Stack<TreeNode> stack = new Stack<TreeNode>();
TreeNode temp = node;
// 当栈不为空,或者当前结点不为空
while (temp!=null || stack.size()>0){
// 存在左子树
while (temp!=null){
stack.push(temp);
temp = temp.left;
}
// 栈非空
if (!stack.isEmpty()){
// 出栈
temp = stack.pop();
// 访问当前结点
System.out.print(temp.val+" ");
temp = temp.right;
}
}
}
// 后序递归遍历二叉树--> 左右根的顺序
public void postOrder(TreeNode node){
if (node==null){
return;
}
// 递归调用,访问当前结点的左孩子结点
postOrder(node.left);
// 递归调用,访问当前结点的右孩子结点
postOrder(node.right);
// 访问当前结点
System.out.print(node.val+" ");
}
// 后序非递归遍历二叉树--> 左右根的顺序
public void noRecPostOrder(TreeNode node){
// 同样是需要利用栈
Stack<TreeNode> stack = new Stack<TreeNode>();
TreeNode temp = node;
while (node!=null){
// 左子树入栈
for (; node.left!=null; node=node.left) {
stack.push(node);
}
// 当前结点无右子树或者右子树已经输出
while (node!=null && (node.right==null || node.right== temp)){
// 访问当前结点
System.out.print(node.val+" ");
// 记录上一个已经输出的结点
temp = node;
if (stack.empty()){
return;
}
node = stack.pop();
}
// 处理右子树。
stack.push(node);
node = node.right;
}
}
// 层次遍历二叉树
public void levelOrder(TreeNode node){
// 借助队列
Queue<TreeNode> queue = new LinkedList<TreeNode>();
/**
* 添加到队列
* Queue 中 add() 和 offer()都是用来向队列添加一个元素。
* 在容量已满的情况下,add() 方法会抛出IllegalStateException异常,offer() 方法只会返回 false 。
*/
queue.offer(node);
while (!queue.isEmpty()){ // 当队列非空的时候
// 从队列中删除第一个元素
TreeNode root = queue.poll();
if (root!=null){ // 该结点非空
// 访问该结点
System.out.print(root.val+" ");
}
// 如果左孩子结点非空,将左孩子结点入队
if (root.left!=null){
queue.offer(root.left);
}
// 如果右孩子结点非空,将右孩子结点入队
if (root.right!=null){
queue.offer(root.right);
}
}
}
public static void main(String[] args) {
BinTree binTree = new BinTree();
TreeNode treeNode = binTree.creat();
System.out.println("先序递归遍历二叉树");
binTree.preOrder(treeNode);
System.out.println("\n--------------------------------");
System.out.println("先序非递归遍历二叉树");
binTree.noRecPreOrder(treeNode);
System.out.println("\n--------------------------------");
System.out.println("中序递归遍历二叉树");
binTree.midOrder(treeNode);
System.out.println("\n--------------------------------");
System.out.println("中序非递归遍历二叉树");
binTree.noRecMidOrder(treeNode);
System.out.println("\n--------------------------------");
System.out.println("后序递归遍历二叉树");
binTree.postOrder(treeNode);
System.out.println("\n--------------------------------");
System.out.println("后序非递归遍历二叉树");
binTree.noRecPostOrder(treeNode);
System.out.println("\n--------------------------------");
System.out.println("层次遍历二叉树");
binTree.levelOrder(treeNode);
}
}