树的遍历顺序大体分为三种:先序遍历(先根遍历),中序遍历(中根遍历),后序遍历(后根遍历)。
二叉树的先序、中序、后序遍历是什么意思?
先序:每一棵子树的打印的顺序都是:头--左--右
中序:每一棵子树的打印的顺序都是:左--头--右
后序:每一棵子树的打印的顺序都是:左--右--头
一、递归实现(比较简单):
先序遍历:
//先序打印二叉树所有节点
public static void prePrint(Node head) {
if (head == null) {
return;
}
System.out.println(head);
prePrint(head.left);
prePrint(head.right);
}
中序遍历:
//中序打印二叉树所有节点
public static void inPrint(Node head) {
if (head == null) {
return;
}
inPrint(head.left);
System.out.println(head);
inPrint(head.right);
}
后序遍历:
//后序打印二叉树所有节点
public static void posPrint(Node head) {
if (head == null) {
return;
}
posPrint(head.left);
posPrint(head.right);
System.out.println(head);
}
重点理解递归序
递归序:先序中序后序的实现就是依靠递归序,先序(第一次打印)中序(第二次打印)后序(第三次打印)------>递归序任意节点的数据遍历都到三次
二、非递归实现(稍微难理解)
1.用栈实现先序遍历:
实现步骤:
1.定义一个currentNode当作遍历的辅助节点,并将头节点添加进栈
2.当栈不为空时,弹出节点并打印,然后在有子节点的情况下:先添加右节点进栈,再添加左节点进栈,因为栈遵循先进后出原则,为完成先序遍历(头--左--右)的顺序,需要先添加右边的节点再添加左边的节点
3.直到没有子节点往栈里面添加,并且栈里面的节点全部取出时,退出循环
public static void pre(Node head) {
if (head != null) {
Stack<Node> stack = new Stack<>();
stack.add(head);
Node currentNode = null;
while (!stack.isEmpty()) {
currentNode = stack.pop();
System.out.println(currentNode);
if (currentNode.right != null) {//一定要先把右节点压入栈中,因为从栈里面弹出的顺序是反的
stack.push(currentNode.right);
}
if (currentNode.left != null) {
stack.push(currentNode.left);
}
}
}
}
2.用栈实现中序遍历:
实现思路:
把二叉树看作有限个关于left指针的单链表(只是这么认为,二非真是单链表,因为二叉树的节点有两条指针)。eg:链表一:head-->head.left-->head.left.left-->直到遇到null;链表二:head.right-->head.right.left-->head.right.left.left-->直到遇到null……因为中序遍历要求顺序是左-->头-->右,将left指针的链表节点存入栈,再弹出节点即可得到(需要注意:弹出一个节点,currentNode需要变成右子节点)
实现步骤:
1.定义一个栈用于存放节点
2.currentNode不为空的时候(currentNode是一直往left指针遍历,直到遇到null),将currentNode添加进栈,并且currentNode移动到左子节点,再次判断是否为空,是否需要添加进栈
3.如果碰到currentNode为null了,那么就从栈里面取出一个节点并打印,再把currentNode指向右子节点,再次判断是否为空,是否需要添加进栈
4.直到栈里面的节点被弹出完,currentNode遍历完二叉树的所有子节点遇到null,退出循环
public static void in(Node currentNode) {
if (currentNode != null) {
Stack<Node> stack = new Stack<>();
while (!stack.isEmpty() || currentNode != null) {
if (currentNode != null) {
stack.push(currentNode);
currentNode = currentNode.left;
} else {
currentNode = stack.pop();
System.out.println(currentNode);
currentNode = currentNode.right;
}
}
}
}
3.用栈实现后序遍历
思路:
用栈实现后序遍历类似于先序遍历,不同之处两点:1.往栈里面添加数据的时候先添加左节点,在添加右节点(这样弹出来的顺序就会是"头-->右-->左");2.完成之后,再添加依次进栈,再取出节点,这样弹出节点的顺序就是“左-->右-->头”,满足后序遍历
实现步骤如用栈实现先序遍历,两点区别在思路中阐述清楚,直接上代码
public static void pos(Node head) {
if (head != null) {
Stack<Node> stack = new Stack<>();
Stack<Node> posStack = new Stack<>();
stack.add(head);
Node currentNode = null;
while (!stack.isEmpty()) {
currentNode = stack.pop();
posStack.push(currentNode);
if (currentNode.left != null) {
stack.push(currentNode.left);
}
if (currentNode.right != null) {
stack.push(currentNode.right);
}
}
while (!posStack.isEmpty()) {
System.out.println(posStack.pop());
}
}
}