Java数据结构与算法分析(七)二叉树

简介: 二叉树是一棵特殊的树,其结构简单但很重要。二叉树的特点是每个节点最多有两棵子树,并且有左右之分。

GitHub源码分享

项目主页:https://github.com/gozhuyinglong/blog-demos
本文源码:https://github.com/gozhuyinglong/blog-demos/tree/main/java-data-structures

1. 二叉树(Binary Tree)

二叉树是一棵特殊的,其结构简单但很重要。二叉树的特点是每个节点最多有两棵子树,并且有左右之分。

  • 满二叉树
    如果一棵二叉树的所有叶子节点都在最后一层,称为满二叉树。满二叉树的结点总数 = $2^n-1$ (n为层数)。如下图二叉是的层数为3,其结点总数为$2^3-1=7$
    满二叉树
  • 完全二叉树
    一棵深度为k的有n个结点的二叉树,对树中的节点按从上至下、从左到右的顺序进行编号,如果编号为i(1≤i≤n)的结点与满二叉树中编号为i的结点在二叉树中的位置相同,则这棵二叉树称为完全二叉树。显示下图中a和b是完全二叉树,而c不是完全二叉树(倒数第二层不连续)

完全二叉树

小结:一棵满二叉树一定是一棵完全二叉树;而一棵完全二叉树不一定是满二叉树。

2. 二叉树的五种形态

二叉树是递归定义的,其节点有左右子树之分,逻辑上二叉树有五种基本形态:

二叉树的五种形态

  • 空二叉树(图a)
  • 只有一个根节点的二叉树(图b)
  • 只有左子树(图c)
  • 只有右子树(图d)
  • 完全二叉树(图e)

3. 二叉树的遍历(前序、中序、后序)

  • 前序遍历:先输出父节点,再遍历左子树,最后遍历右子树。
  • 中序遍历:先遍历左子树,再输出父节点,最后遍历右子树。
  • 后序遍历:先遍历左子树,再遍历右子树,最后输出父节点。

小结:用输出父节点的顺序来判断是前序、中序还是后序遍历

4. 代码实现

通过Java代码实现下图中二叉树,并通过三种方式遍历该二叉树(前序、中序、后序)。

二叉树

Node类为节点类,其中element表示节点元素,left为左子节点,right为右子节点。

BinaryTree类实现二叉树的具体操作,如前序遍历、中序遍历、后序遍历。

public class BinaryTreeDemo {
   
   

    public static void main(String[] args) {
   
   

        BinaryTree tree = new BinaryTree();

        Node a = new Node("A");
        Node b = new Node("B");
        Node c = new Node("C");
        Node d = new Node("D");
        Node e = new Node("E");
        Node f = new Node("F");
        Node g = new Node("G");
        Node h = new Node("H");
        Node i = new Node("I");

        tree.setRoot(a);
        a.left = b;
        a.right = c;
        b.left = d;
        b.right = e;
        d.left = h;
        c.left = f;
        c.right = g;
        g.right = i;

        System.out.println("---------------前序遍历");
        tree.preOrder();
        System.out.println("---------------中序遍历");
        tree.inOrder();
        System.out.println("---------------后序遍历");
        tree.postOrder();

    }

    private static class BinaryTree {
   
   

        private Node root; // 根

        public void setRoot(Node root) {
   
   
            this.root = root;
        }

        /**
         * 前序遍历
         */
        public void preOrder() {
   
   
            preOrder(root, 0);
        }

        /**
         * 前序遍历
         *
         * @param node
         * @param depth 层级(用于辅助输出)
         */
        public void preOrder(Node node, int depth) {
   
   

            if (node == null) {
   
   
                return;
            }

            // 输出当前节点
            this.print(node, depth);

            // 递归左子节点
            if (node.left != null) {
   
   
                preOrder(node.left, depth + 1);
            }

            // 递归右子节点
            if (node.right != null) {
   
   
                preOrder(node.right, depth + 1);
            }

        }

        /**
         * 中序遍历
         */
        public void inOrder() {
   
   
            inOrder(root, 0);
        }

        /**
         * 中序遍历
         *
         * @param node
         * @param depth 层级(用于辅助输出)
         */
        public void inOrder(Node node, int depth) {
   
   

            if (node == null) {
   
   
                return;
            }

            // 递归左子节点
            if (node.left != null) {
   
   
                inOrder(node.left, depth + 1);
            }

            // 输出当前节点
            this.print(node, depth);

            // 递归右子节点
            if (node.right != null) {
   
   
                inOrder(node.right, depth + 1);
            }

        }

        /**
         * 后序遍历
         */
        public void postOrder() {
   
   
            postOrder(root, 0);
        }

        /**
         * 后序遍历
         *
         * @param node
         * @param depth 层级(用于辅助输出)
         */
        public void postOrder(Node node, int depth) {
   
   

            if (node == null) {
   
   
                return;
            }

            // 递归左子节点
            if (node.left != null) {
   
   
                postOrder(node.left, depth + 1);
            }

            // 递归右子节点
            if (node.right != null) {
   
   
                postOrder(node.right, depth + 1);
            }

            // 输出当前节点
            this.print(node, depth);

        }

        /**
         * 按照层级输出节点元素
         *
         * @param node
         * @param depth
         */
        private void print(Node node, int depth) {
   
   
            StringBuilder t = new StringBuilder();
            for (int i = 0; i < depth; i++) {
   
   
                t.append("\t");
            }
            System.out.printf("%s%s\n", t.toString(), node.element);
        }
    }

    private static class Node {
   
   
        private final Object element; // 节点元素
        private Node left; // 左子节点
        private Node right; // 右子节点

        public Node(Object element) {
   
   
            this.element = element;
        }
    }
}

输出结果:

---------------前序遍历
A
    B
        D
            H
        E
    C
        F
        G
            I
---------------中序遍历
            H
        D
    B
        E
A
        F
    C
        G
            I
---------------后序遍历
            H
        D
        E
    B
        F
            I
        G
    C
A
相关文章
|
4天前
|
监控 算法 网络协议
Java 实现局域网电脑屏幕监控算法揭秘
在数字化办公环境中,局域网电脑屏幕监控至关重要。本文介绍用Java实现这一功能的算法,涵盖图像采集、数据传输和监控端显示三个关键环节。通过Java的AWT/Swing库和Robot类抓取屏幕图像,使用Socket进行TCP/IP通信传输图像数据,并利用ImageIO类在监控端展示图像。整个过程确保高效、实时和准确,为提升数字化管理提供了技术基础。
35 15
|
9天前
|
存储 算法 Python
文件管理系统中基于 Python 语言的二叉树查找算法探秘
在数字化时代,文件管理系统至关重要。本文探讨了二叉树查找算法在文件管理中的应用,并通过Python代码展示了其实现过程。二叉树是一种非线性数据结构,每个节点最多有两个子节点。通过文件名的字典序构建和查找二叉树,能高效地管理和检索文件。相较于顺序查找,二叉树查找每次比较可排除一半子树,极大提升了查找效率,尤其适用于海量文件管理。Python代码示例包括定义节点类、插入和查找函数,展示了如何快速定位目标文件。二叉树查找算法为文件管理系统的优化提供了有效途径。
41 5
|
10天前
|
缓存 算法 搜索推荐
Java中的算法优化与复杂度分析
在Java开发中,理解和优化算法的时间复杂度和空间复杂度是提升程序性能的关键。通过合理选择数据结构、避免重复计算、应用分治法等策略,可以显著提高算法效率。在实际开发中,应该根据具体需求和场景,选择合适的优化方法,从而编写出高效、可靠的代码。
25 6
|
9天前
|
数据库
数据结构中二叉树,哈希表,顺序表,链表的比较补充
二叉搜索树,哈希表,顺序表,链表的特点的比较
数据结构中二叉树,哈希表,顺序表,链表的比较补充
|
21天前
|
存储 缓存 安全
Java 集合江湖:底层数据结构的大揭秘!
小米是一位热爱技术分享的程序员,本文详细解析了Java面试中常见的List、Set、Map的区别。不仅介绍了它们的基本特性和实现类,还深入探讨了各自的使用场景和面试技巧,帮助读者更好地理解和应对相关问题。
37 5
|
2月前
|
机器学习/深度学习 存储 算法
数据结构实验之二叉树实验基础
本实验旨在掌握二叉树的基本特性和遍历算法,包括先序、中序、后序的递归与非递归遍历方法。通过编程实践,加深对二叉树结构的理解,学习如何计算二叉树的深度、叶子节点数等属性。实验内容涉及创建二叉树、实现各种遍历算法及求解特定节点数量。
97 4
|
2月前
|
算法
分享一些提高二叉树遍历算法效率的代码示例
这只是简单的示例代码,实际应用中可能还需要根据具体需求进行更多的优化和处理。你可以根据自己的需求对代码进行修改和扩展。
|
2月前
|
缓存 算法 Java
本文聚焦于Java内存管理与调优,介绍Java内存模型、内存泄漏检测与预防、高效字符串拼接、数据结构优化及垃圾回收机制
在现代软件开发中,性能优化至关重要。本文聚焦于Java内存管理与调优,介绍Java内存模型、内存泄漏检测与预防、高效字符串拼接、数据结构优化及垃圾回收机制。通过调整垃圾回收器参数、优化堆大小与布局、使用对象池和缓存技术,开发者可显著提升应用性能和稳定性。
53 6
|
2月前
|
存储 缓存 算法
如何提高二叉树遍历算法的效率?
选择合适的遍历算法,如按层次遍历树时使用广度优先搜索(BFS),中序遍历二叉搜索树以获得有序序列。优化数据结构,如使用线索二叉树减少空指针判断,自定义节点类增加辅助信息。利用递归与非递归的特点,避免栈溢出问题。多线程并行遍历提高速度,注意线程安全。缓存中间结果,避免重复计算。预先计算并存储信息,提高遍历效率。综合运用这些方法,提高二叉树遍历算法的效率。
66 5
|
2月前
|
C语言
【数据结构】二叉树(c语言)(附源码)
本文介绍了如何使用链式结构实现二叉树的基本功能,包括前序、中序、后序和层序遍历,统计节点个数和树的高度,查找节点,判断是否为完全二叉树,以及销毁二叉树。通过手动创建一棵二叉树,详细讲解了每个功能的实现方法和代码示例,帮助读者深入理解递归和数据结构的应用。
144 8