java版数据结构:二叉树

引言:什么是树

    树是一种非线性的数据结构,由节点组成,节点之间以边连接。树结构中最重要的特点是,每个节点可以有多个子节点,但每个节点只有一个父节点(除了根节点)。树结构中没有环路,即任意两个节点之间只有唯一的路径。

树结构通常由根节点、子节点、叶子节点、父节点、深度、高度等基本概念组成:


  1. 根节点:树的顶层节点称为根节点,是整棵树的起始节点。

  2. 子节点:每个节点可以有多个子节点,子节点是直接连接到该节点的下一级节点。

  3. 叶子节点:没有子节点的节点称为叶子节点,即树的末端节点。

  4. 父节点:每个节点除了根节点外,都有一个父节点,即其直接连接到它的上一级节点。

  5. 深度:节点的深度是指从根节点到该节点的唯一路径的边数。根节点的深度为0,其子节点的深度为1,依此类推。

  6. 高度:节点的高度是指从该节点到最远叶子节点的最长路径的边数。叶子节点的高度为0,根节点的高度为树的高度。


数与二叉树之间的关系: 

  1. 树是一种更一般化的结构:树是一种非线性的数据结构,由节点和边组成,节点之间以边连接。在树结构中,每个节点可以有多个子节点,但只有一个父节点(除了根节点)。树结构中没有环路,任意两个节点之间只有唯一的路径。

  2. 二叉树是树的特殊形式二叉树是一种特殊的树结构,每个节点最多有两个子节点,分别称为左子节点和右子节点。二叉树具有树的所有特性,但限制了每个节点的子节点数量为最多两个。

  3. 二叉树是树的一种重要实现方式:在实际应用中,二叉树是树结构的一种重要实现方式。通过限制每个节点的子节点数量为两个,可以更方便地进行操作和处理,例如二叉搜索树、堆、表达式树等都是基于二叉树的实现。

二叉树可以看作是树的特殊情况:从结构上看,二叉树可以看作是树的特殊情况,即每个节点最多有两个子节点的树。因此,二叉树是树结构的一种特殊形式,具有更加严格的约束条件。


二叉树

1. 二叉树的概念:

  • 定义:一棵二叉树是节点的一个有限集合,其中每个节点最多有两个子节点,分别称为左子节点和右子节点。二叉树可以为空,或者由一个根节点和两棵分别称为左子树和右子树的二叉树组成。

2. 二叉树的性质:

  • 有序性:二叉树的子树有左右之分,次序不能颠倒,因此二叉树是有序树。
  • 度的限制:二叉树不存在度大于2的节点,每个节点最多有两个子节点。
  • 递归性质:对于任意的二叉树,都是由根节点、左子树和右子树组成的。

3. 满二叉树和完全二叉树的区别:

  • 满二叉树:一棵二叉树,如果每层的节点数都达到最大值,则这棵二叉树就是满二叉树。满二叉树的所有非叶子节点都有两个子节点,且所有叶子节点都在同一层。
  • 完全二叉树:完全二叉树是一种效率很高的数据结构,是由满二叉树演化而来的。对于深度为K,有n个节点的二叉树,当且仅当每个节点都与深度为K的满二叉树中编号从0至n-1的节点一一对应时,称之为完全二叉树。完全二叉树的叶子节点都集中在最下面两层,并且最后一层的叶子节点靠左排列。

4. 二叉树的存储:

  • 二叉树的存储结构分为顺序存储和链式存储。链式存储通过节点之间的引用来表示树的结构,常见的表示方式有孩子表示法和孩子双亲表示法。

 二叉树的基本操作

1. 二叉树的遍历:

  • 前序遍历(Preorder Traversal):先访问根节点,然后递归地前序遍历左子树和右子树。
  • 中序遍历(Inorder Traversal):先递归地中序遍历左子树,然后访问根节点,最后递归地中序遍历右子树。
  • 后序遍历(Postorder Traversal):先递归地后序遍历左子树和右子树,然后访问根节点。
  • 层序遍历(Level Order Traversal):从上到下,从左到右逐层访问二叉树的节点。

2. 二叉树的构建:

  • 手动创建:通过节点的引用关系手动构建二叉树,可以按照前序、中序、后序等方式构建。
  • 根据遍历序列构建:根据二叉树的前序遍历和中序遍历序列或中序遍历和后序遍历序列构建二叉树。

3. 二叉树的存储结构:

  • 链式存储:通过节点之间的引用关系来表示二叉树的结构,常见的链式存储方式有孩子表示法和孩子双亲表示法。
  • 顺序存储:通过数组等数据结构来存储二叉树的节点,通常按照层序遍历的顺序存储节点,可以方便地进行层序遍历。

4. 二叉树的基本操作:

  • 获取节点个数:计算二叉树中节点的个数。
  • 获取叶子节点个数:计算二叉树中叶子节点的个数。
  • 获取第K层节点个数:计算二叉树中第K层节点的个数。
  • 获取二叉树的高度:计算二叉树的高度或深度。
  • 查找特定值的节点:在二叉树中查找特定值的节点。
  • 判断是否为完全二叉树:判断二叉树是否为完全二叉树。

举例:

class Node {
    int value;
    Node left;
    Node right;

    Node(int value) {
        this.value = value;
        this.left = null;
        this.right = null;
    }
}

public class BinaryTree {
    private Node root;

    // 获取树中节点的个数
    public int size(Node root) {
        if (root == null) {
            return 0;
        }
        return 1 + size(root.left) + size(root.right);
    }

    // 获取叶子节点的个数
    public int getLeafNodeCount(Node root) {
        if (root == null) {
            return 0;
        }
        if (root.left == null && root.right == null) {
            return 1;
        }
        return getLeafNodeCount(root.left) + getLeafNodeCount(root.right);
    }

    // 获取第K层节点的个数
    public int getKLevelNodeCount(Node root, int k) {
        if (root == null || k < 1) {
            return 0;
        }
        if (k == 1) {
            return 1;
        }
        return getKLevelNodeCount(root.left, k - 1) + getKLevelNodeCount(root.right, k - 1);
    }

    // 获取二叉树的高度
    public int getHeight(Node root) {
        if (root == null) {
            return 0;
        }
        int leftHeight = getHeight(root.left);
        int rightHeight = getHeight(root.right);
        return 1 + Math.max(leftHeight, rightHeight);
    }

    // 检测值为value的元素是否存在
    public Node find(Node root, int val) {
        if (root == null) {
            return null;
        }
        if (root.value == val) {
            return root;
        }
        Node leftResult = find(root.left, val);
        Node rightResult = find(root.right, val);
        return leftResult != null ? leftResult : rightResult;
    }

    // 层序遍历
    public void levelOrder(Node root) {
        if (root == null) {
            return;
        }
        Queue<Node> queue = new LinkedList<>();
        queue.offer(root);
        while (!queue.isEmpty()) {
            Node current = queue.poll();
            System.out.print(current.value + " ");
            if (current.left != null) {
                queue.offer(current.left);
            }
            if (current.right != null) {
                queue.offer(current.right);
            }
        }
    }

    // 判断一棵树是不是完全二叉树
    public boolean isCompleteTree(Node root) {
        if (root == null) {
            return true;
        }
        Queue<Node> queue = new LinkedList<>();
        queue.offer(root);
        boolean flag = false;
        while (!queue.isEmpty()) {
            Node current = queue.poll();
            if (current == null) {
                flag = true;
            } else {
                if (flag) {
                    return false;
                }
                queue.offer(current.left);
                queue.offer(current.right);
            }
        }
        return true;
    }
}

针对二叉树各种操作的测试代码:

public class BinaryTreeTest {
    public static void main(String[] args) {
        BinaryTree binaryTree = new BinaryTree();

        // 创建一棵二叉树
        Node root = new Node(1);
        root.left = new Node(2);
        root.right = new Node(3);
        root.left.left = new Node(4);
        root.left.right = new Node(5);
        root.right.left = new Node(6);

        // 测试获取节点个数
        System.out.println("节点个数:" + binaryTree.size(root));

        // 测试获取叶子节点个数
        System.out.println("叶子节点个数:" + binaryTree.getLeafNodeCount(root));

        // 测试获取第K层节点个数
        int k = 2;
        System.out.println("第" + k + "层节点个数:" + binaryTree.getKLevelNodeCount(root, k));

        // 测试获取二叉树的高度
        System.out.println("二叉树的高度:" + binaryTree.getHeight(root));

        // 测试查找特定值的节点
        int valueToFind = 5;
        Node foundNode = binaryTree.find(root, valueToFind);
        if (foundNode != null) {
            System.out.println("找到值为 " + valueToFind + " 的节点");
        } else {
            System.out.println("未找到值为 " + valueToFind + " 的节点");
        }

        // 测试层序遍历
        System.out.println("层序遍历结果:");
        binaryTree.levelOrder(root);

        // 测试判断是否为完全二叉树
        System.out.println("\n是否为完全二叉树:" + binaryTree.isCompleteTree(root));
    }
}

运行结果:


 二叉树的存储:

二叉树的存储结构主要包括顺序存储和链式存储两种方式。

顺序存储:

  • 顺序存储是将二叉树的节点按照某种顺序依次存储在数组中。通常采用完全二叉树的顺序存储方式,即按照从上到下、从左到右的顺序依次存储节点。对于完全二叉树,可以通过数组的下标来表示节点之间的父子关系。例如,对于数组中下标为i的节点,其左子节点的下标为2i+1,右子节点的下标为2i+2,父节点的下标为(i-1)/2。
  • 顺序存储的优点是可以节省存储空间,但缺点是对于非完全二叉树会造成空间浪费,而且插入和删除节点时需要移动大量元素。
  • 顺序存储方式示例:

    public class ArrayBinaryTree {
        private int[] array; // 用数组存储二叉树的节点数据
    
        public ArrayBinaryTree(int[] array) {
            this.array = array;
        }
    
        // 获取父节点的下标
        private int parent(int index) {
            return (index - 1) / 2;
        }
    
        // 获取左子节点的下标
        private int leftChild(int index) {
            return 2 * index + 1;
        }
    
        // 获取右子节点的下标
        private int rightChild(int index) {
            return 2 * index + 2;
        }
    
        public void printTree() {
            for (int i = 0; i < array.length; i++) {
                System.out.println("Node " + array[i] + " - Parent: " + array[parent(i)] +
                        ", Left Child: " + array[leftChild(i)] + ", Right Child: " + array[rightChild(i)]);
            }
        }
    
        public static void main(String[] args) {
            int[] array = {1, 2, 3, 4, 5, 6, 7};
            ArrayBinaryTree binaryTree = new ArrayBinaryTree(array);
            binaryTree.printTree();
        }
    }

链式存储:

  • 链式存储是通过节点之间的引用关系来表示二叉树的存储结构。每个节点包含数据域和指向左右子节点的引用。链式存储方式更直观和灵活,适用于任意形状的二叉树,不会浪费空间。常见的链式存储方式包括孩子表示法和孩子双亲表示法。
  • 孩子表示法:每个节点包含左孩子和右孩子的引用。这种方式简单直观,但可能会导致节点之间的指向关系不够清晰。
  • 孩子双亲表示法:每个节点包含左孩子、右孩子和父节点的引用。通过父节点的引用可以方便地找到当前节点的父节点,便于在树中进行上行操作。
  • 链式存储方式示例:

    class Node {
        int value;
        Node left;
        Node right;
    
        public Node(int value) {
            this.value = value;
            this.left = null;
            this.right = null;
        }
    }
    
    public class BinaryTree {
        private Node root;
    
        public BinaryTree(Node root) {
            this.root = root;
        }
    
        public void printTree(Node node) {
            if (node == null) {
                return;
            }
            System.out.println("Node " + node.value);
            printTree(node.left);
            printTree(node.right);
        }
    
        public static void main(String[] args) {
            Node node1 = new Node(1);
            Node node2 = new Node(2);
            Node node3 = new Node(3);
            Node node4 = new Node(4);
            Node node5 = new Node(5);
            Node node6 = new Node(6);
            Node node7 = new Node(7);
    
            node1.left = node2;
            node1.right = node3;
            node2.left = node4;
            node2.right = node5;
            node3.left = node6;
            node3.right = node7;
    
            BinaryTree binaryTree = new BinaryTree(node1);
            binaryTree.printTree(binaryTree.root);
        }
    }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/624198.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

水雨情监测系统—实时监测水位信息

TH-SW3水雨情监测系统是一种专门用于实时监测和收集水文气象数据的自动化系统。它能够实时获取区域内降雨和水情数据&#xff0c;并将其存储到数据库中进行分析处理&#xff0c;从而为防汛指挥人员提供及时准确的信息服务。 水雨情监测系统的主要功能包括实时监测水位、流速、流…

第十一届蓝桥杯大赛软件类决赛 Java A 组

文章目录 发现宝藏【考生须知】试题 A: 合数个数试题 B : 含 2 天数试题 C: 本质上升序列试题 D: 迨尺天涯试题 E: 玩具蛇试题 F: 游园安排试题 G: 画廊试题 H: 奇偶覆盖试题 I: 补给试题 J: 蓝跳跳 发现宝藏 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&…

基于C++基础知识的指针

一、变量与指针 在C中&#xff0c;变量是用来存储数据的一个标识符&#xff0c;而指针是一个变量&#xff0c;该变量存储的是另一个变量的地址。 变量可以是不同的数据类型&#xff0c;包括整数&#xff08;int&#xff09;、浮点数&#xff08;float&#xff09;、字符&#…

deveco studio 打开官方案例,不显示运行按钮。

就拿官方的search举例好了 git 地址 https://gitee.com/harmonyos/samples/tree/master/ETSUI/Search 使用deveco studio打开Search项目&#xff0c;打开Tools->Device-Manager中的Local Emulator本地模拟器&#xff0c; 此时会发现&#xff0c;运行按钮是灰色的&#xff0…

OVZ虚拟化:解锁高性能的虚拟化利器

欢迎来到我的博客&#xff0c;代码的世界里&#xff0c;每一行都是一个故事 OVZ虚拟化&#xff1a;解锁高性能的虚拟化利器 前言OVZ虚拟化简介OVZ虚拟化的优势OVZ虚拟化的应用场景OVZ虚拟化的部署与管理 前言 在当今快节奏的数字时代&#xff0c;虚拟化技术是推动云计算和容器…

通用人工智能将如何重塑未来

通用人工智能(AGI)是一种人工智能&#xff0c;具有与人类一样的获取知识、应用知识解决问题和理解能力。与专门处理受限任务的狭义人工智能系统不同&#xff0c;AGI寻求发展先进的认知技能&#xff0c;以促进在不同情况下完成复杂任务。AGI是一种人工智能&#xff0c;试图模仿人…

下载源代码并交叉编译riscv FreeBSD系统和内核

RISCV系统曾经让人神秘到无法接触&#xff0c;交叉编译更是只有耳闻&#xff0c;现在随着RISCV的普及&#xff0c;它们神秘的面纱已经被慢慢揭开。 交叉编译作为RISCV系统中的一个重要环节&#xff0c;也随着RISCV的普及而变得更加容易理解和操作。交叉编译允许开发者在一个平…

部署达梦数据库主从配置详细操作DM8

服务器配置 主库 192.168.81.128 实例名 dm-1 从库 192.168.81.129 实例名 dm-2 以下安装部署主从服务器都操作 关闭防火墙 systemctl stop firewalld && systemctl disable firewalld 注意安装前必须创建 dmdba 用户&#xff0c;禁止使用 root 用户安装数据库。…

下载element-ui报错

此错误表示尝试从npm注册表下载“resize observer polyfill”包时超时。这可能是由于网络连接问题或npm注册表服务器的问题。 要解决此问题&#xff0c;您可以尝试以下步骤&#xff1a; 1.重试npm install命令&#xff1a;有时&#xff0c;网络问题会导致临时超时。再次运行npm…

BGP基本配置练习

要求&#xff1a;通过使用BGP来实现所有设备的环回都能ping通 实验的思路 完成所有路由器的IGP配置 使用直连接口建立EBGP对等体关系 使用环回接口建立IBGP对等体关系 使用connect-interface命令修改IBGP的源IP地址 使用next-hop-local命令修改路由传递的下一…

Funakoshi — LipiDye Ⅱ脂滴活细胞成像试剂

Funakoshi LipiDye II是一款适用于长时间活细胞成像以观察动态脂滴&#xff08;LDS&#xff09;合成、移动或降解的绿色荧光染料&#xff1b;是LipiDye&#xff08;货号&#xff1a;FDV-0010&#xff09;的升级版&#xff0c;同时具备超强的光稳定性和高灵敏度等特点。 ➧ 产品…

Cartoon Colections Flower Path 2

高质量的花为Unity游戏引擎优化! 移动优化场景 这款10款3D花卉系列,超过+55种颜色!点击 配有高品质的室内植物和花卉模型。 所有对像都可以在可视化中使用。 - 1024x1024,纹理贴图 - Poly计数:平均8500~125500 tris 下载:​​Unity资源商店链接资源下载链接 效果图:

长难句打卡5.14

This is now a question for Gloria Mackenzie, an 84-year-old widow who recently emerged from her small, tin-roofed house in Florida to collect the biggest undivided lottery jackpot in history. 翻译&#xff1a;这是84岁的孤寡老人歌莉娅 麦肯齐当前所面临的问题…

【正版系统】海外短剧系统功能介绍,前端uniapp+开源。

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言 一、海外短剧系统功能介绍 二、搭建要求 1.系统要求 总结 前言 短剧作为一种快速、紧凑的娱乐形式&#xff0c;正逐渐受到更多海外观众的喜爱。这种需求增长为…

移动端自动化测试工具 Appium 之持续集成

文章目录 一、背景二、前置条件三、代码部分1、pom.xml文件配置2、main入口代码 四、Jenkins 部分1、下载Jenkins2、安装插件3、job配置4、选择构建 五、工程目录六、报告示例七、总结 一、背景 持续集成是老生话谈的事情&#xff0c;用的好不好&#xff0c;看自己公司与使用场…

【链路层和局域网】

文章目录 链路层和局域网网络节点的连接方式数据链路层和局域网链路层导论链路层&#xff1a;上下文链路层服务链路层在哪里实现&#xff1f;适配器通信错误检测奇偶校验校验和&#xff1a;CRC&#xff08;循环冗余校验&#xff09;多点访问链路和协议多路访问协议MAC&#xff…

OpenNJet:引领下一代云原生应用引擎

文章目录 一、前言二、什么是OpenNJet 应用引擎三、OpenNJet的优势3.1 性能无损动态配置3.2 灵活的CoPilot框架3.3 支持HTTP/33.4 支持国密3.5 企业级应用3.6 高效安全 四、centos 安装4.1 生成njet.repo4.2 更新yum 缓存4.3 安装 njet 或 njet-otel 五、OpenNJet配置与部署5.1…

【Nginx <一>⭐️】Nginx 的初步了解以及安装使用

目录 &#x1f44b;前言 &#x1f440;一、 Nginx 介绍 &#x1f331;二、 安装使用 &#x1f49e;️ 三、 总结 &#x1f4eb;四、 章末 &#x1f44b;前言 小伙伴们大家好&#xff0c;前段时间主要在学习 Elasticsearch 相关的知识&#xff0c;花了两周的时间吧&#x…

【Linux系统编程】第十八弹---进程状态(上)

✨个人主页&#xff1a; 熬夜学编程的小林 &#x1f497;系列专栏&#xff1a; 【C语言详解】 【数据结构详解】【C详解】【Linux系统编程】 目录 1、操作系统进程 1.1、进程背景 1.2、进程如何在CPU上运行的&#xff1f; 1.2、进程状态 2、Linux的进程状态 2.1、如何描…

【VUE】VUE3绘制箭头组件

效果预览&#xff1a; 长、宽、粗细等等根据情况合理调整即可。 组件&#xff1a; <template><div class"line" :style"props.arrowsColor"></div> </template><script setup> import { defineProps, ref, onMounted } fr…