二叉树遍历(递归 +迭代)

二叉树的遍历

二叉树——是一种 典型的非线性 数据结构。 而 在计算机程序中,遍历本身是一种线性操作。因此,二叉树的遍历,本质是非线性关联的节点转换成 一个线性 的序列,再 进行线性遍历。

遍历类型

  • 深度遍历

    • 前序遍历(根-> 左-> 右)
    • 中序遍历( 左->根-> 右)
    • 后续遍历( 左-> 右->根)
  • 广度遍历

    • 层序遍历(一层一层的 遍历)

实例

二叉树 :
在这里插入图片描述

二叉树节点
public class TreeNode {
    //数据内容
    public int data;
    //左孩子节点
    public TreeNode leftChild;
    //右孩子节点
    public TreeNode rightChild;

    public TreeNode(int data) {
        this.data = data;
    }

    public int getData() {
        return data;
    }

    public void setData(int data) {
        this.data = data;
    }

    public TreeNode getLeftChild() {
        return leftChild;
    }

    public void setLeftChild(TreeNode leftChild) {
        this.leftChild = leftChild;
    }

    public TreeNode getRightChild() {
        return rightChild;
    }

    public void setRightChild(TreeNode rightChild) {
        this.rightChild = rightChild;
    }

    @Override
    public String toString() {
        return "TreeNode{" +
                "data=" + data +
                '}';
    }
}
构建实例中的二叉树
 public static TreeNode createBinaryTree(){
        
        TreeNode root=new TreeNode(3);
        
        root.leftChild=new TreeNode(2);

        root.leftChild.leftChild=new TreeNode(9);
        
        root.leftChild.rightChild=new TreeNode(7);
        
        
        root.rightChild=new TreeNode(8);
        root.rightChild.rightChild=new TreeNode(4);
        
        return  root;
    }

深度遍历
  • 递归法
 /**
     * 递归前序遍历
     * @param root
     */
    public static void preOrderTraval(TreeNode root){

        if(root!=null){
            //根
            System.out.print("  递归前序->"+root.data  );
            //左
            preOrderTraval(root.leftChild);
            //右
            preOrderTraval(root.rightChild);
        }

    }

    /**
     * 递归中序遍历
     * @param root
     */
    public static void middleOrderTraveral(TreeNode root){
        if(root!=null){
            //左
            middleOrderTraveral(root.leftChild);
            //根
            System.out.print(" 递归中序->"+root.data);
            //右
            middleOrderTraveral(root.rightChild);
        }
    }

    /**
     * 递归后续遍历
     * @param root
     */
    public static void postOrderTraveral(TreeNode root){
        if(root!=null){
            //左
            postOrderTraveral(root.leftChild);
            //右
            postOrderTraveral(root.rightChild);
            //根
            System.out.print(" 递归后续->"+root.data);
        }
    }
  • 迭代法
  1. 前序遍历
/**
     * 迭代前序遍历方法一
     *
     * @param root
     */
    public static void preOrderTraveralByStackA(TreeNode root) {
        //用栈来回溯节点路径
        Stack<TreeNode> treeNodeStack = new Stack<>();

        while (root != null || !treeNodeStack.isEmpty()) {
            //当节点不为null的时候,一直压入栈中(从根节点沿着 左节点一头扎到底)
            while (root != null) {
                treeNodeStack.push(root);

                System.out.println("迭代前序 " + root.data);

                root = root.leftChild;
            }

            //当节点为null的时候,出栈,获取null 的父节点
            TreeNode stackTopNode = treeNodeStack.pop();
            //root切换到 父节点的右节点
            root = stackTopNode.rightChild;

        }
    }

    /**
     * 跌打前序遍历方法二: 由于我们遍历顺序 是 根,左,右,结合栈的出栈规则,我们应该按照  根 ,右 ,左 压入栈中。
     *
     * @param root
     */
    public static void preOrderTraveralByStackB(TreeNode root) {

        Stack<TreeNode> treeNodeStack = new Stack<>();
        //压入根节点
        treeNodeStack.push(root);

        while (!treeNodeStack.isEmpty()) {
            //出栈
            TreeNode popNode = treeNodeStack.pop();
            System.out.println(" 迭代前序B->" + popNode.data);

            if (popNode.rightChild != null) {
                treeNodeStack.push(popNode.rightChild);
            }

            if (popNode.leftChild != null) {
                treeNodeStack.push(popNode.leftChild);
            }
        }

    }
  1. 中序遍历
 /**
     * 迭代中序遍历
     *
     * @param root
     */
    public static void middleOrderTraveralByStack(TreeNode root) {
        //用栈来回溯节点路径
        Stack<TreeNode> treeNodeStack = new Stack<>();

        while (root != null || !treeNodeStack.isEmpty()) {
            //当节点不为null的时候,一直压入栈中(从根节点沿着 左节点一头扎到底)
            while (root != null) {
                treeNodeStack.push(root);
                root = root.leftChild;
            }

            //当节点为null的时候,出栈,获取null 的父节点
            TreeNode stackTopNode = treeNodeStack.pop();

            System.out.println("迭代中序 " + stackTopNode.data);
            //root切换到 父节点的右节点
            root = stackTopNode.rightChild;

        }
    }

3.后续遍历

 /**
     * 迭代 后续遍历
     * @param root
     */
    public static void  postOrderTraveralByStackA(TreeNode root){

        //用栈来回溯节点路径
        Stack<TreeNode> treeNodeStack = new Stack<>();
        //上一个访问的node
        TreeNode preNode=null;

        while (root != null || !treeNodeStack.isEmpty()) {
            //当节点不为null的时候,一直压入栈中(从根节点沿着 左节点一头扎到底)
            while (root != null) {
                treeNodeStack.push(root);
                root = root.leftChild;
            }

            //当节点为左节点null的时候,获取null 的父节点,此时 我们要访问 父节点的 右节点,所以父节点并没有出栈
            //因此会导致1 个问题:如果父节点 的右节点不为null时,需要入栈,从而导致,父节点一定会出现第二次被访问。所以需要设置标志控制
            TreeNode stackTopNode = treeNodeStack.peek();

            if(stackTopNode.rightChild==null||stackTopNode.rightChild==preNode){
                //如果该节点的右节点为null 或者 stackTopNode节点已经被访问过了(因为它的右节点和)
                //真正出栈
                treeNodeStack.pop();

                System.out.println(" 后续遍历-》 "+stackTopNode.data);
                root=null;

            }else{
                //切换到右节点
                root=stackTopNode.rightChild;

            }
            preNode=stackTopNode;

        }

    }



    /**
     * 迭代后续遍历双栈法
     * 思路:  后续遍历(左, 右, 根) 可以 由 前序遍历(根 ,左 右) 转换而来。
     *      因此,前序遍历 转换 成————》右,左,根 ————反转(通过栈)
     * @param root
     */
    public static void  postOrderTraveralByDoubleStack(TreeNode root){

        Stack<TreeNode> treeNodeStack=new Stack<>();

        Stack<TreeNode> reserveStack=new Stack<>();

        treeNodeStack.push(root);

        while (!treeNodeStack.isEmpty()){
            TreeNode popNode = treeNodeStack.pop();

            reserveStack.push(popNode);

            //由于需要 ,先右,后左,所以。先将左压入栈
            if(popNode.leftChild!=null){
                treeNodeStack.push(root.leftChild);
            }

            if(popNode.rightChild!=null){
                treeNodeStack.push(root.rightChild);
            }

        }

        //输出
        while (!reserveStack.isEmpty()){

            TreeNode pop = reserveStack.pop();

            System.out.println(" 双栈法-》" +pop.data);
        }

    }
广度遍历
  /**
     * 广度遍历
     * @param root
     */
    public static  void  levelOrderTraversal(TreeNode root){
        LinkedList<TreeNode> deque=new LinkedList<>();
        deque.add(root);

        while (!deque.isEmpty()){

            TreeNode pop = deque.poll();
            System.out.println("广度遍历  "+ pop.data);

            if(pop.leftChild!=null){
                deque.add(pop.leftChild);
            }

            if(pop.rightChild!=null){
                deque.add(pop.rightChild);

            }
        }

    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值