二叉树的先序中序以及后序遍历(递归 && 非递归)

Posted bywallance

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了二叉树的先序中序以及后序遍历(递归 && 非递归)相关的知识,希望对你有一定的参考价值。

树节点定义:

class TreeNode {
         int val;
         TreeNode left;
         TreeNode right;
         TreeNode(int x) { 
         val = x; 
         }
     }

递归建立二叉树:

    //递归建立二叉树
    public static void BuildTree(TreeNode node, int data){
        if(node == null){
            node = new TreeNode(data);
        }
        
        if(data <= node.val){
            if(node.left == null){
                node.left = new TreeNode(data);
            }else{
                BuildTree(node.left, data);
            }
        }
        
        if(data > node.val){
            if(node.right == null){
                node.right = new TreeNode(data);
            }else{
                BuildTree(node.right, data);
            }
        }    
    }

 

 

1、先序遍历

遍历方式:根节点-->左节点-->右节点

递归先序遍历:

    //先序递归遍历二叉树
    public static List<Integer> preTravese(TreeNode root,List<Integer> arr){
        if(root == null)
            return arr;
        if(root != null){
            arr.add(root.val);
            arr = preTravese(root.left,arr);
            arr = preTravese(root.right,arr);
        }
        return arr;
    }

非递归遍历:

对于任意一个结点p

1)访问结点p,并将p入栈

2)将p变为p的左孩子结点,如果p的不为空,循环至 1); 否则弹出当前栈顶使用p接收,将p变为p的右孩子结点;

3)当p结点为null并且栈为空时,结束循环。

代码:

    //非递归先序遍历
    public static List<Integer> preorderTraversal(TreeNode root){
        List<Integer> arr = new ArrayList<Integer>();
        if(root == null){
            return arr;
        }
        Stack<TreeNode> ts = new Stack<TreeNode>();
        TreeNode ptr = root;
        while( ptr != null || !ts.isEmpty()){
            while(ptr != null){
                arr.add(ptr.val);
                ts.push(ptr);
                ptr = ptr.left;
            }
            if( !ts.isEmpty()){
                ptr = ts.pop();
                ptr = ptr.right;
            }
        }
        return arr;
    }

 

 

2、中序遍历

遍历方式: 左子树-->根节点-->右子树

递归中序遍历:

    //中序递归遍历二叉树
    public static List<Integer> inTravese(TreeNode root,List<Integer> arr){
        if(root == null)
            return arr;
        if(root != null){
            arr = inTravese(root.left,arr);
            arr.add(root.val);
            arr = inTravese(root.right,arr);
        }
        return arr;
    }

非递归中序遍历:

对于任意一个结点p

1)当结点不为null,将结点压栈;

2)将p更新为它的左孩子,如果左孩子不为空,循环至 1);否则弹出栈顶元素赋值给p,访问p结点,p更新为p的右孩子;

3)当p为null 并且栈为空时结束循环。

代码:

    //中序非递归遍历
    public static List<Integer> inorderTraversal(TreeNode root){
        List<Integer> arr = new ArrayList<Integer>();
        if(root == null){
            return arr;
        }
        Stack<TreeNode> ts = new Stack<TreeNode>();
        TreeNode ptr = root;
        while( ptr != null || !ts.isEmpty() ){
            while(ptr != null){
                ts.push(ptr);
                ptr = ptr.left;
            }
            if(!ts.isEmpty()){
                ptr = ts.pop();
                arr.add(ptr.val);
                ptr = ptr.right;
            }
        }
        return arr;
    }

 

3、后序遍历

遍历方式:左子树-->右子树-->根节点

递归遍历:

    //后序递归遍历二叉树
    public static List<Integer> lastTravese(TreeNode root,List<Integer> arr){
        if(root == null)
            return arr;
        if(root != null){
            arr = lastTravese(root.left,arr);
            arr = lastTravese(root.right,arr);
            arr.add(root.val);
        }
        return arr;
    }

非递归遍历:

对于任一结点P,将其入栈,然后沿其左子树一直往下搜索,直到搜索到没有左孩子的结点,此时该结点出现在栈顶,但是此时不能将其出栈并访问,因为其右孩子还没有被访问。

接下来按照相同的规则对其右子树进行相同的处理,当访问完其右孩子时,该结点又出现在栈顶,此时可以将其出栈并访问。

这样就可以保证正确的访问顺序。

可以看出,在这个过程中,每个结点都两次出现在栈顶,只有在第二次出现在栈顶时,才能访问它。因此需要多设置一个变量标识该结点是否是第一次出现在栈顶。

代码:

首先新建一个类来记录结点是否是第一次弹栈:

//新建一个类,用来记录该结点是不是第一次弹栈
class NewTreeNode{
    TreeNode ptr;
    boolean isFirst;
    public NewTreeNode(TreeNode ptr){
        this.ptr = ptr;
        this.isFirst = true;
    }
}

非递归后序遍历二叉树:

    //后序非递归遍历二叉树
    public static List<Integer> lastTraverse(TreeNode root){
        List<Integer> arr = new ArrayList<Integer>();
        if(root == null){
            return arr;
        }
        Stack<NewTreeNode> nts = new Stack<NewTreeNode>();
        NewTreeNode nptr = null;
        TreeNode ptr = root;
        while( ptr!= null || !nts.isEmpty()){
            while(ptr != null){
                nptr = new NewTreeNode(ptr);
                nts.push(nptr);
                ptr = ptr.left;
            }
            
            if(!nts.isEmpty()){
                nptr = nts.pop();
                if(nptr.isFirst){
                    nptr.isFirst = false;
                    nts.push(nptr);
                    ptr = nptr.ptr.right;
                }else{
                    arr.add(nptr.ptr.val);
                    //ptr置为null,因为此时它的左右子树都已经访问完毕
                    ptr = null;
                }
            }
        }
        return arr;
    }

}

 

以上是关于二叉树的先序中序以及后序遍历(递归 && 非递归)的主要内容,如果未能解决你的问题,请参考以下文章

算法练习28:非递归方式遍历二叉树的先序中序后序

用递归和非递归方式实现二叉树的先序中序后序遍历

二叉树的先序中序后序遍历

二叉树遍历的三种方法:先序遍历,中序遍历,后序遍历

输出二叉树的先序中序和后序遍历序列

树——二叉树的先序中序和后序遍历