介绍
本文提供了二叉树的构造、递归与非递归方式的遍历算法,其中递归方式较为简单。但在实际应用中,递归的遍历方式适用于递归深度不高的算法中,其一般使用非递归方式来解决。
二叉树建树
实验一:输入测试数据序列:A B # D # # C # #
构造二叉树示意图:
非递归遍历二叉树的原理
递归方式遍历二叉树较为简单,本文不做过多描述。非递归方式需要用到栈作为辅助数据结构来实现,非递归遍历二叉树的主要原理在于:利用栈的后进先出性质,来安排二叉树的左右子树的先后遍历次序。例如,
1、若使用栈对二叉树进行先序遍历,我们已知先序遍历是先访问自身,然后访问左子树,最后访问右子树,因此,当一个结点被访问后,我们可将该结点的右子树的根结点先入栈,后将左子树的根结点入栈,最后在出栈时,会先访问左子树,后访问右子树。
2、若使用栈中序遍历二叉树,我们需要将树中最左边的结点入栈,因此需要先通过循环找到树中最左边的结点入栈,出栈时先访问该结点,若该结点有右子树,继续寻找右子树中的最左边的结点,重复上述步骤即可。
3、若使用栈后序遍历二叉树,我们观察后序遍历的结果发现,后序遍历的逆序列,即为先序遍历先访问右子树后访问左子树的结果。因此我们可使用栈,做类似先序遍历的操作,并将结果保存到另一个栈,最后将另一个栈中的结果输出即可。
4、若层序遍历啊二叉树,我们希望二叉树的遍历结果一层一层从上到下,从左到右,均有先后顺序,因此可使用队列作为辅助数据结构,先将根结点入队,当该结点出队时,先将左孩子入队后将右孩子入队。
层序遍历原理示意图:
层序遍历得到访问序列:ABCD
算法描述
包结构:
import java.util.Scanner;
public class BTNode {
protected BTNode lchild;
protected BTNode rchild;
protected Object t;
private static Scanner scanner = new Scanner(System.in);
//构造二叉树
public static BTNode createBTNode(){
String str = scanner.next();
if(str.equals("#")){
return null;
}
BTNode node = new BTNode();
node.t = str;
node.lchild = createBTNode(); //构造左子树
node.rchild = createBTNode(); //构造右子树
return node;
}
//先序遍历
public void preTraverse(BTNode root){
if(root != null){
System.out.println(root.t);
preTraverse(root.lchild);
preTraverse(root.rchild);
}
}
//中序遍历
public void middleTraverse(BTNode root){
if(root != null){
middleTraverse(root.lchild);
System.out.println(root.t);
middleTraverse(root.rchild);
}
}
//后序遍历
public void afterTraverse(BTNode root){
if(root != null){
afterTraverse(root.lchild);
afterTraverse(root.rchild);
System.out.println(root.t);
}
}
//用栈先序遍历
public void preTraverseWithStack(BTNode root){
BTNode stack[] = new BTNode[100];
int top = -1;
if(root != null){
stack[++top] = root;
while(top != -1){
BTNode node = stack[top--];
System.out.println(node.t);
if(node.rchild != null){ //右孩子存在将右边孩子入栈
stack[++top] = node.rchild;
}
if(node.lchild != null){
stack[++top] = node.lchild;
}
}
}
}
//用栈中序遍历
public void middleTraverseWithStack(BTNode root){
BTNode stack[] = new BTNode[100];
int top = -1;
if(root != null){
stack[++top] = root;
BTNode p = root;
while(top != -1 || p !=null){
while(p.lchild != null){
stack[++top] = p.lchild;
p = p.lchild;
}
if(top != -1){
BTNode node = stack[top--];
System.out.println(node.t);
if(node.rchild != null){
stack[++top] = node.rchild;
p = node.rchild;
}
}
}
}
}
//用栈后序遍历,将后序序列反过来,就是先序先遍历右子树后遍历左子树的结果,因此这里使用两个栈,栈2用来反转结果
public void afterTraverseWithStack(BTNode root){
BTNode stack1[] = new BTNode[100];
BTNode stack2[] = new BTNode[100];
int top1 = -1;
int top2 = -1;
if(root != null){
stack1[++top1] = root;
while(top1 != -1){
BTNode node = stack1[top1--];
stack2[++top2] = node;
if(node.lchild != null){
stack1[++top1] = node.lchild;
}
if(node.rchild != null){
stack1[++top1] = node.rchild;
}
}
while(top2 != -1){
System.out.println(stack2[top2--].t);
}
}
}
public void levelTraverseWithQueue(BTNode root){
int max = 100;
BTNode que[] = new BTNode[max];
int front,rear;
front = rear = 0;
if(root != null){
rear = (rear + 1)%max;
que[rear] = root;
while(front != rear){
front = (front + 1)%max;
BTNode node = que[front];
System.out.println(node.t);
if(node.lchild != null){
rear = (rear + 1)%max;
que[rear] = node.lchild;
}
if(node.rchild != null){
rear = (rear + 1)%max;
que[rear] = node.rchild;
}
}
}
}
}
import java.util.Scanner;
public class Main {
public static void main(String [] args){
BTNode root = null;
Scanner scanner = new Scanner(System.in);
System.out.println("选择序号:");
System.out.println("1、构造二叉树:");
System.out.println("2、递归先序遍历:");
System.out.println("3、递归中序遍历:");
System.out.println("4、递归后序遍历:");
System.out.println("5、非递归先序遍历:");
System.out.println("6、非递归中序遍历:");
System.out.println("7、非递归后序遍历:");
System.out.println("8、非递归层序遍历:");
System.out.println("9、退出:");
while(true){
System.out.println("输入操作的序号:");
int index = scanner.nextInt();
switch(index){
case 1:
root = BTNode.createBTNode();
break;
case 2:
root.preTraverse(root);
break;
case 3:
root.middleTraverse(root);
break;
case 4:
root.afterTraverse(root);
break;
case 5:
root.preTraverseWithStack(root);
break;
case 6:
root.middleTraverseWithStack(root);
break;
case 7:
root.afterTraverseWithStack(root);
break;
case 8:
root.levelTraverseWithQueue(root);
break;
case 9:
scanner.close();
System.exit(0);
break;
}
System.out.println();
}
}
}
结果测试
选择序号:
1、构造二叉树:
2、递归先序遍历:
3、递归中序遍历:
4、递归后序遍历:
5、非递归先序遍历:
6、非递归中序遍历:
7、非递归后序遍历:
8、非递归层序遍历:
9、退出:
输入操作的序号:
1
A B # D # # C # #
输入操作的序号:
4
D
B
C
A
输入操作的序号:
7
D
B
C
A
输入操作的序号:
8
A
B
C
D
输入操作的序号:
总结
本文提供了二叉树的构造、先序、中序、后序、层序的递归与非递归方式的遍历算法,使用Java描述了这些算法,最终通过一组数据来对上述算法进行测试。