Java实现二叉树,三种遍历的递归和非递归方法实现以及解释
直接上代码,树的结构:
class TreeNode{
int val;
TreeNode left;
TreeNode right;
public TreeNode(int val){
this.val = val;
}
}
先序遍历(递归)
public static void preOrder(TreeNode root){
if(root==null) return;
System.out.print(root.val+" ");
preOrder(root.left);
preOrder(root.right);
}
中序遍历(递归)
public static void inOrder(TreeNode root){
if(root==null) return;
inOrder(root.left);
System.out.print(root.val+" ");
inOrder(root.right);
}
后序遍历(递归)
public static void postOrder(TreeNode root){
if(root==null) return;
postOrder(root.left);
postOrder(root.right);
System.out.print(root.val+" ");
}
可以看到递归的思路非常的直接,不必过多讲解。下面着重看一看非递归的写法:
前序遍历(非递归)
public static void preOrder2(TreeNode root){
Stack<TreeNode> s = new Stack<>();
while(root!=null || !s.isEmpty()){
while(root!=null){
System.out.print(root.val+" ");
s.push(root);
root = root.left;
}
if(!s.isEmpty()){
root=s.pop();
root=root.right;
}
}
}
不使用递归时,我们需要一个栈来存储我们遍历的路径。由于前序遍历的顺序是中左右,所以每到一个根节点我们先获取它的值,然后找左子节点,然后再右。所以先遍历到最左,然后再遍历最左的父节点的右子树,这个回溯的过程通过一个栈来实现,每遍历完一个节点的所有子树就将这个节点从栈中弹出。
中序遍历(非递归)
public static void inOrder2(TreeNode root){
Stack<TreeNode> s = new Stack<>();
while(root!=null || !s.isEmpty()){
while(root!=null){
s.push(root);
root = root.left;
}
if(!s.isEmpty()){
root = s.pop();
System.out.print(root.val+" ");
root = root.right;
}
}
}
中序遍历和先序遍历思路相同,只是改变一下读取数据的时机,在遍历完左边再读取数据。
后序遍历(非递归)
public static void postOrder2(TreeNode root){
Stack<TreeNode> s1 = new Stack<>();
Stack<TreeNode> s2 = new Stack<>();
s1.push(root);
while(!s1.isEmpty()){
root = s1.pop();
s2.push(root);
if(root.left!=null){
s1.push(root.left);
}
if(root.right!=null){
s1.push(root.right);
}
}
while(!s2.isEmpty()){
System.out.print(s2.pop().val+" ");
}
}
后续遍历和前面的思路不同,由于后续遍历需要最后遍历根节点,所以需要另一个数据结构来保存我们需要输出的路径,我们选择再使用一个栈。
一共使用两个栈,s2用来保存后续序列,s1用来遍历二叉树。
我们希望得到的结果是左右中,但是因为栈的特性,s2入栈的顺序应该是中右左。首先我们把s1走到的节点加入s2作为中,然后如果s1这个节点有左子节点,先将左子节点加入s1,如果有右子节点,再将右子节点加入s1。你可能要问不是说好的中右左,为什么这里又是先左后右呢?因为s1也是一个栈,从s1中pop() 的时候顺序还要反过来,所以先加左,在加右。
最后,s2中已经保存好了我们需要的后序序列的逆序,只需要循环出栈遍历即可。
运行测试类以及结果:
测试类:
public static void main(String[] args) {
TreeNode root = new TreeNode(0);
root.left = new TreeNode(1);
root.right = new TreeNode(2);
root.left.left = new TreeNode(3);
root.left.right = new TreeNode(4);
root.right.left = new TreeNode(5);
root.right.right = new TreeNode(6);
BinaryTree bTree = new BinaryTree();
System.out.println("Recursive-----------|");
bTree.preOrder(root);
System.out.println();
bTree.inOrder(root);
System.out.println();
bTree.postOrder(root);
System.out.println();
System.out.println("Non-Recursive-------|");
bTree.preOrder2(root);
System.out.println();
bTree.inOrder2(root);
System.out.println();
bTree.postOrder2(root);
}
}
结果:
Recursive-----------|
0 1 3 4 2 5 6
3 1 4 0 5 2 6
3 4 1 5 6 2 0
Non-Recursive-------|
0 1 3 4 2 5 6
3 1 4 0 5 2 6
3 4 1 5 6 2 0
Process finished with exit code 0