二叉树的前序遍历、中序遍历、后序遍历---java递归非递归实现

首先访问根节点,再遍历左树,再遍历右树,注意。在遍历左、右子树时,也按照先访问根节点,再遍历左树,再遍历右树。例如下图前序遍历结果为:631254978

  • 中序遍历

首先遍历左子树,再访问根节点,再遍历右子树。在遍历左、右子树时,仍然先遍历左子树,再访问根结点,最后遍历右子树。例如下图中序遍历结果为:123456789

  • 后序遍历

首先遍历左子树,然后遍历右子树,最后访问根结点,在遍历左、右子树时,仍然先遍历左子树,然后遍历右子树,最后遍历根结点。例如下图后序遍历结果为:214538796

 代码实现,直接可以进行测试

  • 定义二叉树数据结构:
package tree;

/**
 * Created by Administrator on 2019\4\15 0015.
 */
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;
    public TreeNode(int val){
        this.val = val;
    }

    public int getVal() {
        return val;
    }

    public void setVal(int val) {
        this.val = val;
    }

    public TreeNode getLeft() {
        return left;
    }

    public void setLeft(TreeNode left) {
        this.left = left;
    }

    public TreeNode getRight() {
        return right;
    }

    public void setRight(TreeNode right) {
        this.right = right;
    }
}
  • 二叉树递归非递归实现
package tree;

import java.util.Stack;

/**
 * Created by Administrator on 2019\4\15 0015.
 */
public class MyTreeNode {
    public static void main(String[] args) {
//      二叉树初始化
        TreeNode root = MyTreeNode.init();
        System.out.println("前序遍历");
        preOrder(root);
        System.out.println();
        System.out.println("中序遍历");
        inOrder(root);
        System.out.println();
        System.out.println("后序遍历");
        postOrder(root);
        System.out.println();
        System.out.println("非递归前序遍历");
        normalPreOrder(root);
        System.out.println();
        System.out.println("非递归中序遍历");
        normalInOrder(root);
        System.out.println();
        System.out.println("非递归后序遍历");
        normalPostOrder(root);

    }



    public static void printNode(TreeNode treeNode){
        System.out.print(treeNode.getVal());
    }

    /**
     * 前序遍历
     * @param root:根节点
     */
    public static void preOrder(TreeNode root){
        printNode(root);
        if (root.getLeft() != null){
            preOrder(root.getLeft());
        }
        if (root.getRight() != null){
            preOrder(root.getRight());
        }
    }
    /**
     * 非递归前序遍历
     * @param root:根节点
     */
    public static void normalPreOrder(TreeNode root){
        Stack<TreeNode> stack = new Stack<>();
        TreeNode node = root;
        while (node != null || stack.size()>0){
            if (node != null) {
                printNode(node);
                stack.push(node);
                node = node.getLeft();
            } else {
                node = stack.pop();
                node = node.getRight();
            }
        }
    }


    /**
     * 中序遍历
     * @param root:根节点
     */
    public static void inOrder(TreeNode root){
        if (root.getLeft() != null){
            inOrder(root.getLeft());
        }
        printNode(root);
        if (root.getRight() != null){
            inOrder(root.getRight());
        }
    }

    /**
     * 非递归中序遍历
     * @param root:根节点
     */
    public static void normalInOrder(TreeNode root){
        Stack<TreeNode> stack = new Stack<>();
        TreeNode node = root;
        while (node != null || stack.size() > 0) {
            if (node != null) {
                stack.push(node);
                node = node.getLeft();
            } else {
                node = stack.pop();
                printNode(node);
                node = node.getRight();
            }
        }

    }

    /**
     * 后序遍历
     * @param root:根节点
     */
    public static void postOrder(TreeNode root) {
        if (root.getLeft() != null){
            postOrder(root.getLeft());
        }
        if (root.getRight() != null) {
            postOrder(root.getRight());
        }
        printNode(root);
    }

    /**
     * 非递归后序遍历
     * @param root:根节点
     */
    public static void normalPostOrder(TreeNode root){
        Stack<TreeNode> stack = new Stack<>();
        //构造一个中间栈来存储逆后续遍历的结果
        Stack<TreeNode> out = new Stack<>();
        TreeNode node = root;
        while (node != null || stack.size() > 0) {
            if (node != null) {
                stack.push(node);
                out.push(node);
                node = node.getRight();
            } else {
                node = stack.pop();
                node = node.getLeft();
            }
        }
        while (out.size() > 0) {
            printNode(out.pop());
        }
    }


    public static TreeNode init(){
        TreeNode A = new TreeNode(6);
        TreeNode B = new TreeNode(3);
        TreeNode C = new TreeNode(9);
        TreeNode D = new TreeNode(1);
        TreeNode E = new TreeNode(5);
        TreeNode F = new TreeNode(7);
        TreeNode G = new TreeNode(2);
        TreeNode H = new TreeNode(4);
        TreeNode I = new TreeNode(8);
        A.left = B;
        B.left = D;
        B.right = E;
        D.right = G;
        E.left = H;
        A.right = C;
        C.left = F;
        F.right = I;
        return A;
    }

}
  • 输出结果
前序遍历
631254978
中序遍历
123456789
后序遍历
214538796
非递归前序遍历
631254978
非递归中序遍历
123456789
非递归后序遍历
214538796

 

二叉树递归遍历过程中,前序、中序和后序遍历的工作栈状态变化反映了函数调用栈中递归调用的顺序和状态。递归遍历本质上是利用程序运行时的调用栈来实现栈帧的管理。以下是对前序、中序和后序遍历递归实现过程中工作栈状态变化的详细分析。 ### 前序遍历中的工作栈状态变化 前序遍历递归实现中,访问根节点的操作发生在递归调用左子树和右子树之前。因此,工作栈中会依次压入根节点的调用帧,直到遇到空节点。例如,在遍历左子树时,每进入一个节点,该节点的调用帧被压入栈中,直到左子树为空。随后,栈顶的调用帧被弹出,并继续处理右子树。这一过程会持续到所有节点被访问完毕。 ### 中序遍历中的工作栈状态变化 中序遍历递归实现中,访问根节点的操作发生在递归调用左子树之后、右子树之前。因此,工作栈的状态变化表现为先将左子树的所有节点的调用帧依次压入栈中,直到最左下角的节点。此时,栈顶的调用帧被弹出,访问该节点,然后处理右子树。这一过程确保了左子树被完全处理后,才访问根节点,再处理右子树。 ### 后序遍历中的工作栈状态变化 后序遍历递归实现中,访问根节点的操作发生在递归调用左子树和右子树之后。因此,工作栈的状态变化表现为先将左子树的所有节点的调用帧依次压入栈中,直到遇到空节点。随后,栈顶的调用帧被弹出并处理右子树。在右子树处理完成后,根节点的调用帧才会被弹出,并访问根节点。这一过程确保了左子树和右子树都被完全处理后,才访问根节点。 ### 三种遍历方式的对比 - **前序遍历**:根节点的访问操作在递归调用左右子树之前,因此工作栈中根节点的调用帧会被优先压入栈中。 - **中序遍历**:根节点的访问操作在左子树处理完成后进行,因此工作栈中左子树的调用帧会被优先压入栈中,而根节点的调用帧在栈顶等待访问。 - **后序遍历**:根节点的访问操作在递归调用左右子树之后,因此工作栈中左右子树的调用帧会被优先压入栈中,而根节点的调用帧在栈顶等待访问。 ### 示例代码 以下为前序、中序和后序遍历递归实现代码,展示了递归调用栈的管理方式: ```c // 前序遍历 void PreOrder(BiTNode *T) { if (T != NULL) { visit(T); // 访问根节点 PreOrder(T->lChild); // 递归遍历左子树 PreOrder(T->rChild); // 递归遍历右子树 } } // 中序遍历 void InOrder(BiTNode *T) { if (T != NULL) { InOrder(T->lChild); // 递归遍历左子树 visit(T); // 访问根节点 InOrder(T->rChild); // 递归遍历右子树 } } // 后序遍历 void PostOrder(BiTNode *T) { if (T != NULL) { PostOrder(T->lChild); // 递归遍历左子树 PostOrder(T->rChild); // 递归遍历右子树 visit(T); // 访问根节点 } } ``` ### 工作栈状态变化的总结 - **前序遍历**:根节点的调用帧优先被压入栈中,随后处理左子树和右子树。 - **中序遍历**:左子树的调用帧优先被压入栈中,随后处理根节点和右子树。 - **后序遍历**:左右子树的调用帧优先被压入栈中,随后处理根节点。 在递归实现中,工作栈的状态变化直接反映了递归调用的顺序和逻辑,从而确保遍历结果的正确性。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值