二叉树的遍历-非递归方式
分别用非递归的方式实现二叉树的先序遍历、中序遍历和后续遍历
非递归方式实现二叉树的先序遍历。
过程:
1.申请一个新的栈,记为stack, 然后将二叉树的头结点head压入stack中。
2.从stack中弹出栈顶结点,记为cur,然后打印cur结点的值,再将结点cur的右孩子(不为空的话)先压入stack中,最后将cur的左孩子(不为空的话)压入stack中。
3.不断重复步骤2,直到stack为空,全部过程结束。
实现代码如下:
public void preOrderUnRecur(Node head){
System.out.print("pre-order: ");
if(head != null){
Stack<Node> stack = new Stack<Node>();
stack.add(head);
while(!stack.isEmpty()){
head = stack.pop();
System.out.print(head.value + " ");
if(head.right != null){
stack.push(head.right);
}
if(head.left != null){
stack.push(head.left);
}
}
}
System.out.println();
}
非递归方式实现二叉树的中序遍历
过程:
1.申请一个新的栈,记为stack。初始时,令变量cur = head;
2.先把cur结点压入栈中,对以cur结点为头的整棵子树来说,依次把左边界压入栈中,即不停地令cur=cur.left,然后重复步骤2。
3.不断重复步骤2,直到发现cur为空,此时从stack中弹出一个结点,记为node。打印node的值,并且让cur = node.right,然后继续重复步骤2。
4.当stack为空且cur为空时,整个过程停止。
实现代码如下:
public void inOrderUnRecur(Node head){
System.out.print("in-order:");
if(head != null){
Stack<Node> stack = new Stack<>();
while(!stack.isEmpty() || head != null){
if(head != null){
stack.push(head);
head = head.left;
}else{
head = stack.pop();
System.out.println(head.value);
head = head.right;
}
}
}
System.out.println();
}
非递归方式实现二叉树的后续遍历-实现方式一:使用两个栈实现
过程:
1.申请一个栈,记为s1,然后将树的头结点head压入s1中
2.从s1中弹出的结点记为cur,然后依次将cur的左孩子和右孩子压入s1中
3.在整个过程中,每一个从s1中弹出的结点都放进s2里。
4.不断重复步骤2和步骤3,直到s1为空,过程停止。
5.从s2中依次弹出结点并打印,打印的顺序就是后续遍历的顺序。
实现代码如下:
public void posOrderUnRecur(Node head){
System.out.print("pos-order (two stack):");
if(head != null){
Stack<Node> s1 = new Stack<>();
Stack<Node> s2 = new Stack<>();
s1.push(head);
while(!s1.isEmpty()){
head = s1.pop();
s2.push(head);
if(head.left != null){
s1.push(head.left);
}
if(head.right != null){
s1.push(head.right);
}
}
while(!s2.isEmpty()){
System.out.print(s2.pop().value + " ");
}
}
System.out.println();
}
备注: 每棵子树的头结点都最先从s1中弹出,然后把该结点的孩子结点按照先左再右的顺序压入s1,那么从s1弹出的顺序就是从右再左,所以从s1中弹出的顺序就是中、右、左。然后,s2重新收集的过程就是s1的弹出顺序逆序,也就是左、右、中。所以s2从栈顶到栈底的顺序就变成了左、右、中,打印出的结果就是后序遍历的结果。
非递归方式实现二叉树的后续遍历-实现方式二:使用一个栈实现
过程:
1.申请一个栈,记为stack,将头结点压入stack,同时设置两个变量h和c。在整个流程中,h代表最近一次弹出并打印的结点,c代表stack的栈顶结点。初始时h为头结点,c为null。
2.每次令c等于当前Stack的栈顶结点,但是不从stack中弹出,此时分以下三种情况:
(1)如果c的左孩子不为null,且h不等于c的左孩子,也不等于c的右孩子,则把c的左孩子压入stack中。解释一下这么做的原因,首先h的意义是最近一次弹出并打印的结点,所以如果h等于c的左孩子或者右孩子,说明c的左子树与右子树打印完毕,此时不应该再将c的左孩子放入stack中。否则,说明左子树还没处理过,那么此时将c的左孩子压入stack中。
(2)如果条件1不成立,并且c的右孩子不为null,h不等于c的右孩子,则把c的右孩子压入stack中。含义是如果h等于c的右孩子,说明c的右子树已经打印完毕,此时不应该再将c的右孩子放入stack中。否则,说明右子树还没被处理过,此时将c的右孩子压入stack中。
(3)如果条件(1)和条件(2)都不成立,说明c的左子树和右子树都已经打印完毕,那么从stack中弹出c并打印,然后令h = c。
3.一直重复步骤2,直到stack为空,过程停止。
实现代码如下:
public void posOrderUnRecur2(Node h){
System.out.print("pos-order (one stack) :");
if(h != null){
Stack<Node> stack = new Stack<>();
stack.push(h);
Node c = null;
while(!stack.isEmpty()){
c = stack.peek();
if(c.left != null && h != c.left && h != c.right){
stack.push(c.left);
}else if(c.right != null && h != c.right){
stack.push(c.right);
}else{
System.out.print(stack.pop() + " ");
h = c;
}
}
}
System.out.println();
}
测试函数:
public static void main(String[] args) {
PrintTree pt = new PrintTree();
/*
建树
1
/ \
2 3
/ \ / \
4 5 6 7
*/
Node root = new Node(1);//创建根结点
root.left = new Node(2);
root.right = new Node(3);
root.left.left = new Node(4);
root.left.right = new Node(5);
root.right.left = new Node(6);
root.right.right = new Node(7);
pt.preOrderUnRecur(root);
System.out.println();
pt.inOrderUnRecur(root);
System.out.println();
pt.posOrderUnRecur(root);
System.out.println();
pt.posOrderUnRecur2(root);
System.out.println();
}
测试结果:
上一篇: “换芯法”医主板
下一篇: 基础实验6-2.1-列出连通集-编程题