数据结构 二叉树

越努力越幸运!

转载自:https://www.javazhiyin.com/12976.html 

实现了二叉树的深度和广度优先遍历

深度优先遍历:

对每一个可能的分支路径深入到不能再深入为止,而且每个结点只能访问一次。而二叉树的深度优先遍历分为先序遍历,中序遍历和后续遍历。

  • 先序遍历:先访问根,在访问左子树,最后访问右子树,总结就是“根左右”;
  • 中序遍历:先访问左子树,再访问根,最后访问右子树,总结就是“左根右”;
  • 后序遍历:先访问左子树,再访问右子树,最后访问根,总结就是“左右根”;

通常采用递归的方式实现遍历,非递归方式需要结合栈(后进先出)的特点实现。

广度优先遍历:

又叫层次遍历,从上往下对每一层依次访问,在每一层中,从左往右(也可以从右往左)访问结点,访问完一层就进入下一层,直到没有结点可以访问为止。

广度优先遍历的非递归的通用做法是采用队列(先入先出)。

用该图来理解深度优先遍历和广度优先遍历:

  • 深度优先遍历:该图为一个无向图,假设我们从A开始进行深度优先搜索,第二点可以是B、C、D中任意一个,假设访问的是B,那么路径为A - B - E,搜索完成后直接退回B,搜索其下一个子节点,完成B之后退到A,搜索C节点,以此类推,直到找出需要的解。
  • 广度优先遍历:假设从A开始探索,第二点可以是B、C、D中任意一个,假设访问的是B,那么接下来再从C、D中选择一个,假设最终的路线是A-B-C-D,然后同理再去遍历B、C、D的子节点,直到所有的点都被遍历鼓过。

二叉排序树:

二叉排序树是一种特殊的二叉树,其树的根节点的左侧总是小于根节点,节点的右侧总是大于根节点。如下图所示。

图解两种遍历算法:

该图为输入了:35 20 15 16 29 28 30 40 50 45 55之后生成的二叉排序树。

先序遍历(递归):35 20 15 16 29 28 30 40 50 45 55
中序遍历(递归):15 16 20 28 29 30 35 40 45 50 55
后序遍历(递归):16 15 28 30 29 20 45 55 50 40 35
先序遍历(非递归):35 20 15 16 29 28 30 40 50 45 55
中序遍历(非递归):15 16 20 28 29 30 35 40 45 50 55
后序遍历(非递归):16 15 28 30 29 20 45 55 50 40 35
广度优先遍历:35 20 40 15 29 50 16 28 30 45 55

程序实现:

/**
*实体类
*/
public class Tree {

    Tree treeLeft;
    Tree treeRight;//创建了树的两个分支,声明类型自己本身树,目的是每新建一个分支依旧为树的一个节点
    int data;

    Tree(int data){
        this.data = data;//data在这里是树节点(或分支)的值
        treeLeft = treeRight = null;
    }
}

/**
*运行主程序
*/
public class TreeMain {

    /**
     * 二叉排序树;左边是小于等于,右边是大于根节点。
     * @param root
     * @param data
     * @return
     */
    public static Tree insert(Tree root, int data) {
        if (root == null) {
            return new Tree(data);//新建树节点
        }else {
            Tree cur;
            if (data <= root.data) {//小的放在左侧
                cur = insert(root.treeLeft,data);//递归一直到root为空时,调用第一个IF实现新建树节点
                root.treeLeft = cur;
            }else {//大的放在右侧
                cur = insert(root.treeRight,data);
                root.treeRight = cur;
            }
            return root;
        }
    }

    /**
     * 深度优先遍历分为,先序、中序和后序遍历
     */

    /**
     * 递归法实现先序遍历,并打印
     * @param root
     */
    public static void preOrder(Tree root){
        if(root == null) return;
        System.out.print(root.data + " ");
        preOrder(root.treeLeft);
        preOrder(root.treeRight);
    }

    /**
     * 递归法实现中序遍历,并打印
     * @param root
     */
    public static void inOrder(Tree root){
        if(root == null) return;
        inOrder(root.treeLeft);//用递归的方法一直找到树的最左侧
        System.out.print(root.data + " ");
        inOrder(root.treeRight);
    }

    /**
     * 递归方法实现后序遍历,并打印
     * @param root
     */
    public static void postOrder(Tree root){
        if(root == null) return;
        postOrder(root.treeLeft);
        postOrder(root.treeRight);
        System.out.print(root.data + " ");
    }

    /**
     * 非递归方法实现先序遍历,并打印
     * @param root
     */
    public static void preOrder2(Tree root){
        LinkedList<Tree> stack = new LinkedList<>();
        Tree currentRoot = null;
        stack.push(root);
        while (!stack.isEmpty()){
            currentRoot = stack.pop();
            System.out.print(currentRoot.data + " ");
            //栈是先入后出,需要先入栈右分支
            if (currentRoot.treeRight != null){
                stack.push(currentRoot.treeRight);
            }
            if (currentRoot.treeLeft != null){
                stack.push(currentRoot.treeLeft);
            }
        }
    }

    /**
     * 非递归方法实现中序遍历,并打印
     * @param root
     */
    public static void inOrder2(Tree root){
        LinkedList<Tree> stack = new LinkedList<>();
        Tree currentRoot = root;
        while (currentRoot !=null || !stack.isEmpty()){
            //遍历到二叉树的最左侧
            while (currentRoot != null){
                stack.push(currentRoot);
                currentRoot = currentRoot.treeLeft;
            }
            currentRoot = stack.pop();
            System.out.print(currentRoot.data + " ");
            currentRoot = currentRoot.treeRight;
        }
    }

    /**
     * 非递归方法实现后序遍历,并打印
     * @param root
     */
    public static void postOrder2(Tree root){
        LinkedList<Tree> stack = new LinkedList<>();
        Tree currentRoot = root;
        Tree rightRoot = null;
        while (currentRoot != null || !stack.isEmpty()){
            while (currentRoot != null){
                stack.push(currentRoot);
                currentRoot = currentRoot.treeLeft;
            }
            currentRoot = stack.pop();
            //当前节点没有右节点或上一个结点(已经输出的结点)是当前结点的右结点,则输出当前结点
            while (currentRoot.treeRight == null || currentRoot.treeRight == rightRoot){
                System.out.print(currentRoot.data + " ");
                rightRoot = currentRoot;
                if (stack.isEmpty()){
                    return;
                }
                currentRoot = stack.pop();
            }
            stack.push(currentRoot);//还有未遍历的右侧节点
            currentRoot = currentRoot.treeRight;
        }
    }

    /**
     * 对列法实现二叉树广度优先遍历,队列遵循先进先出的规则,适合本方法
     * @param root
     */
    public static void levelOrer(Tree root){
        Queue<Tree> queue = new LinkedList<Tree>();//新增队列

        if(root != null){
            queue.add(root);//将根节点加入队列
        }

        while (!queue.isEmpty()){
            Tree cur = queue.peek();//创建cur的目的是在while循环的时候逐层将树带入,如果直接用root,会导致只能输出一级树
            System.out.print(cur.data + " ");
            queue.remove();
            if (cur.treeLeft != null){
                queue.add(cur.treeLeft);//先将左分支加入队列,之后先输出
            }
            if(cur.treeRight != null){
                queue.add(cur.treeRight);
            }
        }

    }

    /**
     * main函数,输入输出,遍历
     * @param args
     */
    public static void main(String[] args) {

        Scanner sc = new Scanner(System.in);
        System.out.println("请输入数字的个数:");
        int T = sc.nextInt();
        int[] t = new int[T];
        System.out.println("请输入数字,以空格分隔:");
        for (int i = 0; i < T; i++) {
            t[i] = sc.nextInt();
        }

        Tree root = null;
        for (int i = 0; i < T; i++) {
            root = insert(root,t[i]);
        }
        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("非递归先序遍历:");
        preOrder2(root);
        System.out.println();
        System.out.println("非递归中序遍历:");
        inOrder2(root);
        System.out.println();
        System.out.println("非递归后序遍历:");
        postOrder2(root);
        System.out.println();
        System.out.println("广度优先遍历:");
        levelOrer(root);

    }
}
运行结果:

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值