二叉树的前序、中序、后序递归及非递归遍历

前序遍历

二叉树的前序遍历访问顺序是:根节点 -> 左子树 -> 右子树。

递归实现

public void preOrderRecursive(TreeNode root){
    if(root == null) return;
    System.out.println(root.val);
    printPreOrder(root.left);
    printPreOrder(root.right);
}

非递归实现

非递归实现利用栈来实现,主要是利用栈来存储根节点,因为之后需要访问根节点的右孩子。每次在压栈之前,先输出当前节点的值(因为当前节点就是根节点或者子树的根节点)。如果向左走已经为空了,就从栈中弹出节点,并访问弹出节点的右孩子。

public void preOrderNonRecursive(TreeNode root){
    TreeNode node = root;
    Stack<TreeNode> stack = new Stack<>();
    while(node != null || !stack.isEmpty()){
        while(node!=null){
            System.out.println(node.val);
            stack.push(node);
            node = node.left;
        }
        if(!stack.isEmpty()){
             node = stack.pop();
             node = node.right;
        }
    }
}

中序遍历

中序遍历的顺序是:左子树 -> 根节点 -> 右子树

递归实现

public void inOrderRecursive(TreeNode root){
    if(root == null) return;
    printInOrder(root.left);
    System.out.println(root.val);
    printInOrder(root.right);
}

非递归实现

中序遍历的非递归实现其实只是调换了左孩子和根节点的位置。因此我们不断向左遍历并且压栈,直到没有左孩子节点为止。然后弹栈,并且输出当前节点(因为压入栈的其实是:根节点-左孩子,所以弹栈的时候,先将左孩子弹出访问,然后再弹出根节点访问)。然后再访问该节点的右孩子节点。

public void inOrderNonRecursive(TreeNode root){
    TreeNode node = root;
    Stack<TreeNode> stack = new Stack<>();
    while(node != null || !stack.isEmpty()){
        while(node!=null){
            stack.push(node);
            node = node.left;
        }
        if(!stack.isEmpty()) {
            node = stack.pop();
            System.out.println(node.val);
            node = node.right;
        }
    }
}

后序遍历

后序遍历的访问顺序是:左子树 -> 右子树 -> 根节点

递归实现

public void postOrderRecursive(TreeNode root){
    if(root == null) return;
    printPostOrder(root.left);
    printPostOrder(root.right);
    System.out.println(root.val);
}

非递归实现

后序遍历的非递归实现是三种遍历方式中最复杂的一种。因为它需要先访问右孩子节点之后才能访问根节点。因此需要一个变量来存储前一个访问的节点,用判断根节点的右孩子是否访问过。并且在访问节点右孩子节点访问过或者为空的情况下,才从栈中弹出根节点。

public void postorderNonRecursive(TreeNode root) {
    if(root == null) return ;
    Stack<TreeNode> stack = new Stack<>();
    TreeNode node = root;
    TreeNode pre = null;
    while(!stack.isEmpty() || node!=null){
        while (node!=null){
            stack.push(node);
            node = node.left;
        }
        if(!stack.isEmpty()){
            node = stack.peek();
            if(node.right==null||node.right == pre){
                stack.pop();
                System.out.println(node.val);
                pre = node;
                node = null;
            }
            else{
                node = node.right;
            }
        }
    }
}

总结

二叉树的前序、中序、后序遍历的递归实现都是很容易理解和实现的。重点是它们的非递归实现,利用的栈来存储之后需要再次访问的节点。但是无论是哪种实现,都需要我们能够流畅的写出来。另外,这三种的时间复杂度都是O(n),空间复杂度也是O(n)。下一篇的莫里斯(Morris)遍历,可以将空间复杂度优化到O(1)。

发布了5 篇原创文章 · 获赞 0 · 访问量 113

猜你喜欢

转载自blog.csdn.net/danmo_wuhen/article/details/104338518