二叉树的非递归前序,中序,后序遍历的Java实现

二叉树的非递归前序,中序,后序遍历的Java实现

二叉树是经常使用的树形结构,其遍历也是经常用到的。利用递归可以很简单的写出前中后序的遍历。本文采用非递归方式进行遍历,先上代码,解释在后面。

此代码是一个抽象类,节点的操作在具体类中实现。前序遍历有两种实现,一种是标准实现(与中序遍历很相似),一种是我自己的实现。

package travelTree;

import java.util.Stack;

public abstract class TreeTravelwithNoRecursive {

    public void myfirstOrder(TreeNode root) {
        if(root == null) return;
        Stack<TreeNode> stack = new Stack<TreeNode>();
        stack.push(root);
        while(!stack.isEmpty()) {
            TreeNode node = stack.pop();
            doWithNode(node);
            if(node.right != null) {
                stack.push(node.right);
            }
            if(node.left != null) {
                stack.push(node.left);
            }
        }
    }

    public void firstOrder(TreeNode root) {
        Stack<TreeNode> stack = new Stack<TreeNode>();
        TreeNode node = root;
        while( node!=null || !stack.empty() ) {
            while(node!= null) {
                stack.push(node);
                doWithNode(node);
                node = node.left;
            }
            if( !stack.isEmpty() ) {
                node = stack.pop();
                node = node.right;
            }
        }
    }

    public void middleOrder(TreeNode root) {
        Stack<TreeNode> stack = new Stack<TreeNode>();
        TreeNode node = root;
        while( node!=null || !stack.empty() ) {
            while(node!= null) {
                stack.push(node);
                node = node.left;
            }
            if( !stack.isEmpty() ) {
                node = stack.pop();
                doWithNode(node);
                node = node.right;
            }
        }
    }

    public void myafterOrder(TreeNode root) {
        Stack<TreeNode> stack = new Stack<TreeNode>();
        TreeNode node = root;
        TreeNode pre = null;
        if(root == null)return;
        stack.push(root);
        while( !stack.empty() ) {
            node = stack.peek();
            if((node.left == null && node.right == null)
                    ||(pre!=null && (pre == node.left || pre == node.right))) {
                node = stack.pop();
                doWithNode(node);
                pre = node;
            }
            else {
                if(node.right != null) {
                    stack.push(node.right);
                }
                if(node.left != null) {
                    stack.push(node.left);
                }
            }
        }

    }

    public abstract void doWithNode(TreeNode node);

    public static void main(String[] args) {
        TreeNode root = new TreeNode(1);
        TreeNode n2 = new TreeNode(2);
        TreeNode n3 = new TreeNode(3);
        TreeNode n4 = new TreeNode(4);
        TreeNode n5 = new TreeNode(5);
        TreeNode n6 = new TreeNode(6);
        TreeNode n7 = new TreeNode(7);
        TreeNode n8 = new TreeNode(8);
        root.left = n2;
        root.right = n3;
        n2.left = n4;
        n2.right = n5;
        n3.left = n6;
        n4.left = n7;
        n5.right = n8;

        TreeTravelwithNoRecursive travel = new TreeTravelwithNoRecursive() {

            @Override
            public void doWithNode(TreeNode node) {
                System.out.println(node.val);

            }
        };
//      travel.myfirstOrder(root);
//      travel.firstOrder(root);
//      travel.middleOrder(root);
        travel.myafterOrder(root);
    }
}
package travelTree;
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;

    public TreeNode(int val) {
        this.val = val;

    }

}


三种遍历的规则:

  • 前序遍历:先访问根节点,接着访问左子树,然后是右子树
  • 中序遍历:先访问左子树,接着访问根节点,最后是右子树
  • 后序遍历:先访问左子树,接着访问右子树,最后是根节点


非递归实现:

前序遍历
方法一:

先将根节点入栈

     stack.push(root);

接着是一个循环直到栈为空,循环中做的事情则是,出栈并处理节点;接着若右子树不为空,则入栈;再接着左子树不为空,则入栈

    while(!stack.isEmpty()) {
        TreeNode node = stack.pop();
        doWithNode(node);
        if(node.right != null) {
            stack.push(node.right);
        }
        if(node.left != null) {
            stack.push(node.left);
        }
    }
方法二:

利用一个游标节点node标记当前的位置(初始指向root),当node不为空,或者栈不为空时循环:若node不为空,则将node入栈,并处理节点,同时让node指向其左子树,循环直至node为空;接着若栈不为空,则出栈一个元素,并将node指向其右子树。

    while( node!=null || !stack.empty() ) {
        while(node!= null) {
            stack.push(node);
            doWithNode(node);
            node = node.left;
        }
        if( !stack.isEmpty() ) {
            node = stack.pop();
            node = node.right;
        }
    }


中序遍历
与前序遍历的方法二流程一样,只是处理节点的位置由入栈时改为出栈时

利用一个游标节点node标记当前的位置(初始指向root),当node不为空,或者栈不为空时循环:若node不为空,则将node入栈,同时让node指向其左子树,循环直至node为空;接着若栈不为空,则出栈一个元素,并处理节点,并将node指向其右子树。

    while( node!=null || !stack.empty() ) {
        while(node!= null) {
            stack.push(node);
            node = node.left;
        }
        if( !stack.isEmpty() ) {
            node = stack.pop();
            doWithNode(node);
            node = node.right;
        }
    }


后序遍历
后序遍历其实也有两种实现方式,我这里是易理解的一种

该方法的要点是
- 右子树比左子树先入栈,保证每次节点的左子树在右子树之前遍历到
- 要遍历该节点,则必须保证其左右子树均已遍历过了。如何判断其左右子树均已遍历呢?设置一个pre的节点,记录上次遍历的节点,若上次遍历的是其左子树(无右子树的情况)或右子树,则可以遍历该节点,否则先遍历其左右子树

    node = stack.peek();
    if((node.left == null && node.right == null)
            ||(pre!=null && (pre == node.left || pre == node.right))) {
        node = stack.pop();
        doWithNode(node);
        pre = node;
    }
    else {
        if(node.right != null) {
            stack.push(node.right);
        }
        if(node.left != null) {
            stack.push(node.left);
        }
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值