一.用递归的方式
可以看到用递归的方式只是System.out.print(node.val+" ")位置不同而已
/**
* @description: 二叉树
* @create: 2021-05-22 15:50
**/
public class treeTest {
public static void main(String[] args) {
Node node1=new Node(1);
Node node2=new Node(2);
Node node3=new Node(3);
Node node4=new Node(4);
Node node5=new Node(5);
Node node6=new Node(6);
Node node7=new Node(7);
node1.leftChild=node2;
node1.rightChild=node3;
node2.leftChild=node4;
node2.rightChild=node5;
node3.leftChild=node6;
node3.rightChild=node7;
System.out.println("先序:");
first(node1);
System.out.println();
System.out.println("中序:");
mid(node1);
System.out.println();
System.out.println("后序:");
last(node1);
}
/**
* @Description 先序遍历,头->左->右
* @Date 16:06 2021/5/22
* @Param [node]
* @return void
**/
public static void first(Node node){
if(node==null){
return;
}
System.out.print(node.val+" ");
first(node.leftChild);
first(node.rightChild);
}
/**
* @Description 中序遍历,左->头->右
* @Date 16:06 2021/5/22
* @Param [node]
* @return void
**/
public static void mid(Node node){
if(node==null){
return;
}
mid(node.leftChild);
System.out.print(node.val+" ");
mid(node.rightChild);
}
/**
* @Description 后序遍历,左->右->头
* @Date 16:06 2021/5/22
* @Param [node]
* @return void
**/
public static void last(Node node){
if(node==null){
return;
}
last(node.leftChild);
last(node.rightChild);
System.out.print(node.val+" ");
}
static class Node{
Node parent;
Node leftChild;
Node rightChild;
int val;
public Node(Node parent, Node leftChild, Node rightChild,int val) {
super();
this.parent = parent;
this.leftChild = leftChild;
this.rightChild = rightChild;
this.val = val;
}
public Node(int val){
this(null,null,null,val);
}
public Node(Node node,int val){
this(node,null,null,val);
}
}
}
用递归的方法,每个节点都会执行3次,先序:同一个节点第一次到达就打印
中序:同一个节点第二次到达就打印
后序:同一个节点第三次达到就打印
二.用栈的方式
1.先序:头左右
(1)把头结点先压入栈(2)结点弹出就打印
(3)如有右结点,压入右
(3)如有左结点,压入左
例子:首先放入头结点1,弹出打印1,然后把右结点3放入,再放左结点2,弹出2并打印,然后放入右结点5,然后放入左结点4, 4和5都没有子结点,先弹4,在弹5,然后弹3,然后压入7,然后压入6,弹出6,和7,先序就完成了:1 2 4 5 3 6 7
public static void firstStack(Node node) {
//先加入头结点,然后弹出打印,有右入右,然后有左入左
if (node != null) {
Stack<Node> stack = new Stack<Node>();
stack.push(node);
while (!stack.empty()) {
Node n = stack.pop();
System.out.print(n.val + " ");
if (n.rightChild != null) {
stack.push(n.rightChild);
}
if (n.leftChild != null) {
stack.push(n.leftChild);
}
}
}
}
2.后序:左右头
按照 先头,左,右的方法放入结点,弹出来的结点顺序是1,3,7,6,2,5,4,从右往左看刚好是后序的排列,所以把先弹出来的放入新的栈里
(1)把头结点先压入栈
(2) 结点弹出到另一个栈中
(3)如有左结点,压入左
(3)如有右结点,压入右
public static void lastStack(Node node) {
if (node != null) {
Stack<Node> stack = new Stack<Node>();
Stack<Node> result = new Stack<Node>();
stack.push(node);
while (!stack.empty()) {
Node n = stack.pop();
result.push(n);
if (n.leftChild != null) {
stack.push(n.leftChild);
}
if (n.rightChild != null) {
stack.push(n.rightChild);
}
}
while(!result.empty()){
System.out.print(result.pop().val+" ");
}
}
}
后序的第二种方法,避免了创建另一个stack来完成排序。
public static void lastStack2(Node node) {
if (node != null) {
Stack<Node> stack = new Stack<Node>();
stack.push(node);
Node c=null;
while (!stack.empty()) {
//获取栈顶的位置,但不弹出
c = stack.peek();
//先把左结点全部进栈
if (c.leftChild != null && node!=c.leftChild && node!=c.rightChild) {
stack.push(c.leftChild);
//处理当前栈顶右节点,如果有就入栈
}else if(c.rightChild!=null && node!=c.rightChild){
stack.push(c.rightChild);
}else{
//处理当前栈顶左右节点都处理完成,当前栈顶节点出栈,并且打印,node每次指向的是
//出栈的那个节点
System.out.print(stack.pop().val+" ");
node=c;
}
}
}
}
3.中序:左头右
规则一:整颗数左边界依次压入栈
规则二:当没有左节点时就弹出打印。找到该节点的右数执行规则一
例子:先压入1,2,4,然后弹出4并打印,4没有右数节点,就往回走,弹出2,然后找到2的右数5压栈,
5没有右节点弹出打印,然后弹出1打印,找到1的右节点3执行规则一,把3,6都压栈,6没有右节点,直接弹出打印,然后弹出3,找到3的右节点7,然后入栈,然后7没有节点直接弹出打印
public static void minStack(Node node) {
if (node != null) {
Stack<Node> stack = new Stack<Node>();
while (!stack.empty() || node!=null) {
//如果node为空,说明没有左结点,弹出打印当前结点
if(node!=null){
stack.push(node);
node=node.leftChild;
}else{
//循环加入node!=null,是在node.rightChild为空的情况下,
// 说明该节点左右节点都没有,往回走,出来上一个节点
node=stack.pop();
System.out.print(node.val+" ");
node=node.rightChild;
}
}
}
}