二分搜索树的遍历

二分搜索树的遍历和二叉树的遍历是一致的(二分搜索树的实质本身就是一棵二叉树),直接使用二叉树的遍历即可.
大一的时候数据结构学的还可以,感觉不是特别复杂

二叉树的遍历方式:

  • 深度优先遍历

1.前序遍历
2.中序遍历
3.后序遍历

  • 广度优先遍历

层序遍历


前序遍历

根节点->左孩子->右孩子

二分搜索树的遍历_第1张图片
前序遍历

递归实现

/**
     * 对二叉树进行前序遍历
     */
    public void preOrder(){
        preOrder(root);
    }

    /**
     * 前序遍历的递归方式,深度优先
     * 当前节点->左孩子->右孩子
     * @param node 传入的节点
     */
    private void preOrder(Node node){
        //遍历到叶子节点时,退出当前的路线
        if (node == null){
            return;
        }

        //1.遍历当前节点
        System.out.print(node.data+"->");

        //2.遍历左孩子
        preOrder(node.left);

        //3.遍历右孩子
        preOrder(node.right);
    }

非递归实现

/**
     * 前序遍历的非递归实现方式
     */
    public void preOrderNr(){
        
        //使用栈辅助实现前序遍历
        Stack stack = new Stack<>();
        
        /*
        前序遍历的过程就是先访问当前节点,然后再访问左子树,然后再右子树
        使用栈实现的时候,可以先将当前的节点入栈 
        当前节点出站的时候,分别将右孩子,左孩子入(栈的特点:先进后出)
         */
        stack.push(root);
        //栈不为空时
        while (!stack.isEmpty()){
            Node node = stack.pop();
            //前序遍历当前的节点
            System.out.print(node.data + "->");
            
            //先进后出
            if (node.right != null){
                stack.push(node.right);
            }
            
            if (node.left != null){
                stack.push(node.left);
            }
        }

中序遍历

左孩子->根节点->右孩子

二分搜索树的遍历_第2张图片
中序遍历

递归实现

/**
     * 对中序遍历进行中序遍历
     */
    public void midOrder(){
        midOrder(root);
    }

    /**
     * 中序遍历的递归方式,深度优先
     * 左孩子->当前节点->右孩子
     * @param node 传入的节点
     */
    private void midOrder(Node node){
        if (node == null){
            return;
        }

        //1.中序遍历左孩子
        midOrder(node.left);

        //2.遍历根节点
        System.out.print(node.data+"->");

        //3.遍历右孩子
        midOrder(node.right);
    }

非递归实现


    /**
     * 中序遍历的非递归实现方式
     */
    public void midOrderNr(){

        //使用栈辅助实现前序遍历
        Stack stack = new Stack<>();

        //辅助节点
        Node p = root;
        stack.add(p);

        System.err.println();
        //只要存在左孩子,就将左孩子入栈
        while (!stack.isEmpty()){
            if (p != null && p.left != null){
                stack.add(p.left);
                p = p.left;
            }else {
                p = stack.pop();
                System.out.print(p.data+"->");
                if (p != null && p.right != null){
                    //将右孩子入栈
                    stack.add(p.right);
                    p = p.right;
                }else {
                    p = null;
                }
            }
        }

后序遍历

左孩子->右孩子->根节点


二分搜索树的遍历_第3张图片
后序遍历

递归实现

 /**
     * 二叉树的后序遍历
     */
    public void afterOrder(){
        afterOrder(root);
    }

    /**
     * 左孩子->右孩子->父节点
     * @param node 父节点
     */
    private void afterOrder(Node node) {
        if (node == null){
            return;
        }

        afterOrder(node.left);

        afterOrder(node.right);

        System.out.print(node.data+"->");

    }

非递归实现

/**
     * 后序遍历的非递归实现方式
     */
    public void afterOrderNr(){

       if (root != null){
           Stack stack = new Stack<>();
           stack.push(root);
           Node p;
           while (!stack.isEmpty()){
               p = stack.peek();
               if (p.left != null && root != p.left && root != p.right){
                   stack.push(p.left);
               }else if (p.right != null && root!= p.right){
                   stack.push(p.right);
               }else {
                   System.err.print(stack.pop().data+"->");
                   root = p;
               }
           }
       }
    }

层序遍历

从左到右,从上到下


二分搜索树的遍历_第4张图片
层序遍历
 /**
     * 层序遍历,从左到右,从上到下,一次遍历
     * 借助队列实现
     */
    public void levelOrder(){

        Queue queue = new LinkedList<>();
        /*
         * 遍历过程:
         * 1. 首先根节点入队
         * 2. 每次出队时, 都将当前节点的左右孩子先后入队
         * 3. 如果队列为空的话, 则表示层序遍历结束
         *      5
         *    /   \
         *   3    6
         *  / \    \
         * 2  4     8
         * 针对上面的二分搜索树, 详细描述一下层序遍历步骤
         * 1. 5入队, 队列元素 : head->[5]<-tail
         * 2. 5出队, 5的左子树3, 6入队, 由于队列是先入先出(FIFO), 所以先左后右, 队列元素 : head->[3, 6]<-tail
         * 3. 3出队, 2, 4入队, 队列元素  : head->[6, 2, 4]<-tail
         * 4. 6出队, 左孩子为空,所以8入队, 队列元素  : head->[2, 4, 8]<-tail
         * 5. 2,4,8依次出队, 由于这三个节点都是叶子节点, 无子节点, 所以这三个节点出队后队列为空, 层序遍历完成
         * 6. 按照出队的顺序演示的遍历结果为 : 5 3 6 2 4 8
         */
        queue.add(root);

        while (!queue.isEmpty()){
            Node p = queue.poll();
            System.err.print(p.data+"->");
            if (p.left != null){
                queue.add(p.left);
            }
            if (p.right != null){
                queue.add(p.right);
            }
        }

小结:

相对来说非递归方式的效率会更高,但是递归方式实现逻辑更加清晰

参考博客:
https://blog.csdn.net/davidddl/article/details/75667092
https://blog.csdn.net/love905661433/article/details/82981527

你可能感兴趣的:(二分搜索树的遍历)