您的位置:首页 > 编程语言 > Java开发

Java实现二叉树的递归、非递归遍历

2017-07-23 14:12 447 查看
在计算机科学里,树的遍历是指通过一种方法按照一定的顺序访问一颗树的过程。

对于二叉树,树的遍历通常有四种:先序遍历、中序遍历、后序遍历、广度优先遍历(Breadth Frist Search)(层次遍历)。(前三种亦统称深度优先遍历(Depth First Search))对于多叉树,树的遍历通常有两种:深度优先遍历、广度优先遍历。因为树的定义本身就是递归定义,因此采用递归的方法去实现树的三种遍历不仅容易理解而且代码很简洁。而对于树的遍历若采用非递归的方法,就要采用栈去模拟实现。在三种遍历中,前序和中序遍历的非递归算法都很容易实现,非递归后序遍历实现起来相对来说要难一点。




一.前序遍历

前序遍历按照“根结点-左孩子-右孩子”的顺序进行访问。


1.递归实现

public static void preOrder(TreeNode root){
if(root != null){
System.out.print(root.val + " ");
preOrder(root.left);
preOrder(root.right);
}
}



2.非递归实现

    根据前序遍历访问的顺序,优先访问根结点,然后再分别访问左孩子和右孩子。即对于任一结点,其可看做是根结点,因此可以直接访问,访问完之后,若其左孩子不为空,按相同规则访问它的左子树;当访问其左子树时,再访问它的右子树。因此其处理过程如下:

对于任一结点P:

1)访问结点P,并将结点P入栈;

2)判断结点P的左孩子是否为空,若为空,则取栈顶结点并进行出栈操作,并将栈顶结点的右孩子置为当前的结点P,循环至1);若不为空,则将P的左孩子置为当前的结点P;

3)直到P为NULL并且栈为空,则遍历结束。
public static ArrayList preOrder1(TreeNode root){
Stack<TreeNode> stack = new Stack<TreeNode>();
ArrayList alist = new ArrayList();
TreeNode p = root;
while(p != null || !stack.empty()){
while(p != null){
alist.add(p.val);
stack.push(p);
p = p.left;
}
if(!stack.empty()){
TreeNode temp = stack.pop();
p = temp.right;
}
}
return alist;
}




二.中序遍历

中序遍历按照“左孩子-根结点-右孩子”的顺序进行访问。


1.递归实现

public static void inOrder(TreeNode root){
if(root != null){
inOrder(root.left);
System.out.print(root.val + " ");
inOrder(root.right);
}
}



2.非递归实现

    根据中序遍历的顺序,对于任一结点,优先访问其左孩子,而左孩子结点又可以看做一根结点,然后继续访问其左孩子结点,直到遇到左孩子结点为空的结点才进行访问,然后按相同的规则访问其右子树。因此其处理过程如下:

对于任一结点P,

1)若其左孩子不为空,则将P入栈并将P的左孩子置为当前的P,然后对当前结点P再进行相同的处理;

2)若其左孩子为空,则取栈顶元素并进行出栈操作,访问该栈顶结点,然后将当前的P置为栈顶结点的右孩子;

3)直到P为NULL并且栈为空则遍历结束
public static ArrayList inOrder1(TreeNode root){
ArrayList alist = new ArrayList();
Stack<TreeNode> stack = new Stack<TreeNode>();
TreeNode p = root;
while(p != null || !stack.empty()){
while(p != null){
stack.push(p);
p = p.left;
}
if(!stack.empty()){
TreeNode temp = stack.pop();
alist.add(temp.val);
p = temp.right;
}
}
return alist;
}




三.后序遍历

后序遍历按照“左孩子-右孩子-根结点”的顺序进行访问。

1.递归实现

public static void postOrder(TreeNode root){
if(root != null){
postOrder(root.left);
postOrder(root.right);
System.out.print(root.val + " ");
}
}



2.非递归实现

       后序遍历的非递归实现是三种遍历方式中最难的一种。因为在后序遍历中,要保证左孩子和右孩子都已被访问并且左孩子在右孩子前访问才能访问根结点,这就为流程的控制带来了难题。下面介绍思路。

要保证根结点在左孩子和右孩子访问之后才能访问,因此对于任一结点P,先将其入栈。如果P不存在左孩子和右孩子,则可以直接访问它;或者P存在左孩子或者右孩子,但是其左孩子和右孩子都已被访问过了,则同样可以直接访问该结点。若非上述两种情况,则将P的右孩子和左孩子依次入栈,这样就保证了每次取栈顶元素的时候,左孩子在右孩子前面被访问,左孩子和右孩子都在根结点前面被访问。

public static ArrayList postOrder1(TreeNode root){
ArrayList alist = new ArrayList();
Stack<TreeNode> stack = new Stack<TreeNode>();
if(root == null)
return alist;
TreeNode cur,pre = null;
stack.push(root);
while(!stack.empty()){
cur = stack.peek();
if((cur.left == null && cur.right == null) || (pre != null && (cur.left == pre || cur.right == pre))){
TreeNode temp = stack.pop();
alist.add(temp.val);
pre = temp;
}
else{
if(cur.right != null)
stack.push(cur.right);
if(cur.left != null)
stack.push(cur.left);
}
}
return alist;
}


四.层次遍历  

 树的层次遍历,故名思议,在一棵树中,把节点从左往右,一层一层的,从上往下,遍历输出,这里要用到一种很重要的数据结构,队列,一提到队列,我们就要想到先进先进先,即为先进入队列元素,先接受处理,我们在日常生活中排队时,就是先到的人,先接受服务。
理解好队列,可以很容易的解决树的层此遍历,步骤如下:

 1.首先将根节点放入队列中。

 2.当队列为非空时,循环执行步骤3到步骤5,否则执行6;

 3.出队列取得一个结点,访问该结点;

 4.若该结点的左子树为非空,则将该结点的左子树入队列;

 5.若该结点的右子树为非空,则将该结点的右子树入队列;

 6.结束。

private static void levelOrder(TreeNode root) {
Queue<TreeNode> queue = new LinkedList<TreeNode>();
if(root == null)
return;
queue.offer(root);
while(!queue.isEmpty()){
TreeNode temp  = queue.poll();
System.out.print(temp.val + " ");
if(temp.left != null)
queue.offer(temp.left);
if(temp.right != null)
queue.offer(temp.right);
}
}


五.整个程序完整的代码

package cn.edu.ahui;

/**
* 类信息描述
*
* @author leo;
* @date 2017年7月20日 下午5:17:25
* @version V2.0
* 递归、非递归实现二叉树遍历
*/
import cn.edu.ahui.TreeNode;
import java.util.*;

public class BTraversal{
//递归实现二叉树的前序遍历
public static void preOrder(TreeNode root){
if(root != null){
System.out.print(root.val + " ");
preOrder(root.left);
preOrder(root.right);
}
}

//非递归实现前序遍历
public static ArrayList preOrder1(TreeNode root){
Stack<TreeNode> stack = new Stack<TreeNode>();
ArrayList alist = new ArrayList();
TreeNode p = root;
while(p != null || !stack.empty()){
while(p != null){
alist.add(p.val);
stack.push(p);
p = p.left;
}
if(!stack.empty()){
TreeNode temp = stack.pop();
p = temp.right;
}
}
return alist;
}

//递归实现中序遍历
public static void inOrder(TreeNode root){
if(root != null){
inOrder(root.left);
System.out.print(root.val + " ");
inOrder(root.right);
}
}
//非递归实现中序遍历
public static ArrayList inOrder1(TreeNode root){
ArrayList alist = new ArrayList();
Stack<TreeNode> stack = new Stack<TreeNode>();
TreeNode p = root;
while(p != null || !stack.empty()){
while(p != null){
stack.push(p);
p = p.left;
}
if(!stack.empty()){
TreeNode temp = stack.pop();
alist.add(temp.val);
p = temp.right;
}
}
return alist;
}
//递归实现二叉树的后序遍历
public static void postOrder(TreeNode root){
if(root != null){
postOrder(root.left);
postOrder(root.right);
System.out.print(root.val + " ");
}
}
//非递归实现二叉树的后续遍历
public static ArrayList postOrder1(TreeNode root){
ArrayList alist = new ArrayList();
Stack<TreeNode> stack = new Stack<TreeNode>();
if(root == null)
return alist;
TreeNode cur,pre = null;
stack.push(root);
while(!stack.empty()){
cur = stack.peek();
if((cur.left == null && cur.right == null) || (pre != null && (cur.left == pre || cur.right == pre))){
TreeNode temp = stack.pop();
alist.add(temp.val);
pre = temp;
}
else{
if(cur.right != null)
stack.push(cur.right);
if(cur.left != null)
stack.push(cur.left);
}
}
return alist;
}
//非递归实现二叉树的层次遍历
private static void levelOrder(TreeNode root) {
Queue<TreeNode> queue = new LinkedList<TreeNode>();
if(root == null)
return;
queue.offer(root);
while(!queue.isEmpty()){
TreeNode temp  = queue.poll();
System.out.print(temp.val + " ");
if(temp.left != null)
queue.offer(temp.left);
if(temp.right != null)
queue.offer(temp.right);
}
}

//简单创建一个简单的二叉树
public static TreeNode createBT(){
TreeNode i = new TreeNode("I");
TreeNode h = new TreeNode("H");
TreeNode g = new TreeNode("G");
TreeNode e = new TreeNode("E");
TreeNode f = new TreeNode("F", h, i);
TreeNode d = new TreeNode("D", null, g);
TreeNode c = new TreeNode("C", f, null);
TreeNode b = new TreeNode("B", d, e);
TreeNode root = new TreeNode("A", b, c);
return root;
}

public static void main(String[] args) {
//简单创建普通二叉树
TreeNode root = createBT();
//递归实现前序遍历
preOrder(root);
System.out.println();
//非递归实现前序遍历
for(Object o : preOrder1(root)){
System.out.print(o.toString() + " ");
}
System.out.println();
System.out.println("********************************");
//递归实现中序遍历
inOrder(root);
System.out.println();
for(Object o : inOrder1(root)){
System.out.print(o.toString() + " ");
}
System.out.println();
System.out.println("********************************");
//递归实现后序遍历
postOrder(root);
System.out.println();
//非递归实现后续遍历
for(Object a : postOrder1(root)){
System.out.print(a.toString() + " ");
}
System.out.println();
System.out.println("********************************");
//非递归实现层次遍历
levelOrder(root);
}
}


参考:
http://www.cnblogs.com/LZYY/p/3454778.html http://www.cnblogs.com/NeilHappy/archive/2013/04/04/2999050.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  二叉树 递归 遍历 java