Java 数据结构:什么是树?怎么使用?

java数据结构与算法面试,java面试手写代码 前言 总有一天你会明白,你的努力终究没有白费 年前辞职,人算不如天算,突如其来的疫情完全把自己的计划给打碎了,面试难度简直不亚于一场江苏高考题,后悔、焦虑不安、失眠成了我的生活状态。 从三月底开始投递简历,甭管是什么公司,只要薪资待遇跟之前差不多我都投了。最气人的一次面试经历是一个小公司的HR约我面试,我过去了,填完表格,还没到技术面呢,她看到我的期望薪资是15k+,直接来了一句:“不好意思,我们最多只能给到10k+,所以,您可能不太适合。“我:”???” 慢慢开始怀疑自己了,是不是自己的技术不够好? 阅读详情


一、树

1. 概述

  • 与线性表表示的一一对应的线性关系不同,树表示的是更为复杂的数据元素之间的非线性关系。
  • 直观来看,树是以分支关系定义的层次结构,是 一对多 的关系
  • 树的定义:树 (Tree) 是 n( n>=0 ) 个结点的有限集合
  • 有且仅有一个 根结点 (Root)
  • 当n>1的时,其余结点可分为 m( m>0 ) 个互不相交的有限集T1,T2,…, Tm,其中每一个集合本身又是一棵树,并且称之为根的子树。

树的定义本身是一个递归定义,即在树的定义中又用到树的概念

2. 一些基本术语

  • 树的结点:包含一个数据元素和若干指向其子树的分支
  • 度(degree):结点拥有的子树的数目
  • 度为** 0 的结点称为 叶子**,或** 终端结点**。度不为** 0** 的结点称为 非终端结点 或 分支节点
  • 结点的子树的根,称为该结点的 孩子(child),相应的该结点称为孩子的 双亲(parent)
  • 同一个双亲的孩子之间互称兄弟(sibling)
  • 结点的 祖先 是从根到该结点所经分支上所有的结点。
  • 以某结点为根的子树中的任意一结点都称为该结点的 子孙
  • 结点的 层次(Level)从根开始定义,根为第一层,根的孩子为第二层,以此类推
  • 树中结点的最大层次称为树的 深度(depth)或 高度

二、二叉树

1. 概述

  • 定义:对一般的树加了约束:

  • 每个结点最多两棵子树,即二叉树中不存在 度大于2 的结点

  • 子树有 左右次序 之分

  • 有 5 种形态:

二叉树的形态

  • 满二叉树和完全二叉树(对满二叉树最底层,从右至左删除结点)

2. 重要特性

  • 二叉树,在第 i 层至多有 2i-1 个结点
  • 深度为 k 的二叉树至多有 2k-1 个结点
  • 高度(或深度)为 K 的完全二叉树至少有 2k-2 个 叶子结点
  • 非空二叉树的 叶子结点数 等于度为 2 的结点数加 1,即:n0 = n2 + 1

完全二叉树的 n1 只能是 0 或者 1

  • 一颗度为 m 的二叉树,度为 1 的结点为 n1,度为 2 的结点为 n2,… …,度为 m 的结点数为 nm,则叶子结点数:n0**= 1 + n2****+ 2n3****+…+ (m-1)nm**
  • 具有 n 个结点的完全二叉树,深度为 log2n + 1
  • 编号性质:n 个结点的完全二叉树(其深度为 log2n + 1),对各结点从上到下,从左到右依次编号(1~n)则:若 i 是某结点 a 的编号:
  • 如果 i 不等于 1,则 a 的双亲结点的编号为: ⌊ i/2 ⌋
  • 如果 2i ≤ n, 则 a 的左孩子编号为 2i;如果** 2i > n**, 则 a** 无左孩子**;
  • 如果** 2i + 1 ≤ n**, 则 a 的右孩子编号为** 2i + 1**;如果** 2i + 1> n**, 则 a** 无右孩子**;

三、二叉树的存储结构

1. 顺序存储

  • 用 数组 来存储数据元素
  • 从存储的角度来看,这种顺序存储结构,仅适用于 完全二叉树

因为在最坏的情况下,一个深度为 k 且只有 k 个结点的单支树( 树中不存在度为 2 的结点 ),却需要长度为 2k-1 的一维数组。

2. 链式存储

  • 以 链表 的形式,存储数据元素以及数据元素之间的关系。

链式存储


四、二叉树的遍历

1. 由遍历序列确定二叉树

  • 由 先序和中序,可以确定
  • 由 后序和中序,可以确定(但是注意后序最后一个为根,下一个是右子树根)
  • 由 层次和中序,可以确定

2. 根据遍历序列估计二叉树

  • 前序 遍历序列 和 后序 遍历序列 相同 的树:只有根结点
  • 前序 遍历 和 中序 遍历 相同 的二叉树:所有结点没有左子树(右单分支树
  • 中序 遍历 和 后序 遍历 相同 的二叉树:所有结点没有右子树(左单分支树)
  • 前序遍历 和 后序 遍历 相反 的二叉树:没有左子树或者没有右子树(只有一个叶子结点)高度等于其结点数
  • 前序 遍历 和 中序 遍历 相反 的二叉树:所有结点没有右子树(左单分支树)
  • 中序 遍历 和 后序 遍历 相反 的二叉树:所有结点没有左子树(右单分支树)

3. 遍历和建树代码

  • 二叉树的建树
  • 深度优先遍历(先序,中序和后序)
  • 广度优先遍历(先序,后序)
/* BitTree.java */

package com.java.tree;

import java.util.LinkedList;
import java.util.Queue;

/**
 * Created by Jaco.Young.
 * 2018-06-13 18:26
 */
public class BitTree {

    //代表由先序和中序唯一确定的树的根结点
    private TreeNode root;

    /**
     * 提供给外部调用的方法
     * 字符数组pre表示先序遍历序列,mid表示中序遍历序列
     */
    public void build(char[] pre, char[] mid){
        //将创建树的根结点赋值给 root
        root = buildTree(pre,0, pre.length-1, mid, 0, mid.length-1);
    }

    /**
     * 前提条件,树中不存在重复元素
     * 由先序遍历序列和中序遍历序列,构造二叉树的方法
     * 我们建树的过程总是将序列不断地分割成左子树、右子树
     * lPre、rPre和lMid、rMid,分别就表示要对先序和中序的哪一部分进行建树
     */
    private TreeNode buildTree(char[] pre, int lPre, int rPre, char[] mid, int lMid, int rMid){
        //在先序遍历序列中,找到当前这棵树的根结点
        char root = pre[lPre];

        //在中序遍历序列中,根据先序中的根结点来查找在中序中的位置
        int rootIndex = getRootIndex(mid, lMid, rMid, root);

        //如果没有找到,说明所给的参数异常
        if(rootIndex == -1){
            throw new IllegalArgumentException("Illegal Argument!");
        }

        //计算当前这棵树,左右子树的个数
        //整个中序序列:[左子树(lMid)  root(rootIndex)  右子树(rMid)]
        //左子树[lMid,rootIndex-1]
        int lNum = rootIndex - lMid; //rootIndex-1 -lMid + 1
        //右子树[rootIndex+1,rMid]
        int rNum = rMid - rootIndex;  //rMid - (rootIndex + 1) + 1

        //开始构建当前根结点的左子树和右子树
        //先构建左子树
        TreeNode lchild;  //作为左子树的根结点
        //以当前结点为根的树,没有左子树
        if(lNum == 0){
            lchild = null;
        }else{
            //当前这个树的左子树,仍然是一棵树,递归构造这棵树的左子树
            //设x为当前树先序中左子树最后一个元素的下标,则:x - (lpre + 1) = lNum
            //得:x = lPre + lNum
            lchild = buildTree(pre, lPre + 1, lPre+lNum, mid, lMid, rootIndex - 1);
        }

        //构建右子树
        TreeNode rchild;
        if(rNum == 0){
            rchild = null;
        }else{
            //当前结点的右子树,仍然包含很多节点,需要递归的构造其右子树
            rchild = buildTree(pre, lPre + lNum + 1, rPre, mid, rootIndex + 1, rMid);
        }

        //构造完整的二叉树
        return new TreeNode(root,lchild,rchild);
    }

    //在中序遍历序列中,根据先序中的根结点来查找在中序中的位置
    private int getRootIndex(char[] mid, int lMid, int rMid, char root) {
        for(int i = lMid; i <= rMid; i++){
            if(mid[i] == root){
                return i;
            }
        }
        return -1;
    }

    //二叉树每一个结点的结构
    private class TreeNode{
        //结点中存储的数据
        char item;
        //指向左孩子结点
        TreeNode lChild;
        //指向右孩子结点
        TreeNode rChild;

        //构造方法,完成初始化
        public TreeNode(char item, TreeNode lChild, TreeNode rChild){
            this.item = item;
            this.lChild = lChild;
            this.rChild = rChild;
        }
    }

    //提供三个让外界调用的方法
    public  void preTraverse() {
        preOrder(root);
    }

    public void midTraverse() {
        midOrder(root);
    }

    public void postTraverse() {
        postOrder(root);
    }

    //先序遍历  DLR
    private void preOrder(TreeNode root) {
        if( root != null) {
            //先访问根节点
            System.out.print(root.item + " ");
            //递归访问左子树
            preOrder(root.lChild);
            //递归访问右子树
            preOrder(root.rChild);
        }
    }

    //中序遍历   LDR
    private void midOrder(TreeNode root) {
        if(root != null) {
            //递归访问左子树
            midOrder(root.lChild);
            //访问根
            System.out.print(root.item + " ");
            //递归访问右子树
            midOrder(root.rChild);
        }
    }

    //后续遍历
    // LRD
    private void postOrder(TreeNode root) {
        if(root != null) {
            //递归访问左子树
            postOrder(root.lChild);
            //递归访问右子树
            postOrder(root.rChild);
            //访问根
            System.out.print(root.item + " ");
        }
    }

    //广度优先遍历  BFS
    public void BFS() {
        //创建一个能放TreeNode对象的队列
        Queue<TreeNode> queue = new LinkedList<>();
        //将树的根节点入队列
        queue.add(root);
        //循环执行广度优先遍历
        while(!queue.isEmpty()) {
            //将当前的队头元素出队列
            TreeNode node = queue.remove();
            //访问出队列的节点
            System.out.print(node.item + " ");

            //出队列的节点是否有左孩子,有则将其左孩子入队列
            if(node.lChild != null) {
                //有左孩子
                queue.add(node.lChild);
            }
            //出队列的节点是否有右孩子,如果右,将其右孩子如队列
            if(node.rChild != null) {
                queue.add(node.rChild);
            }
        }
    }
}

/* Test.java*/
package com.java.tree;

/**
 * 测试类
 * Created by Jaco.Young.
 * 2018-06-13 20:16
 */
public class Test {
    public static void main(String[] args){
        //构造先序遍历序列和中序遍历序列
        char[] pre = {'A','B','E', 'K', 'L', 'F', 'D', 'H', 'J'};
        char[] mid = {'K', 'E', 'L', 'B', 'F', 'A', 'H', 'D', 'J'};

        BitTree bitTree = new BitTree();
        //根据遍历序列构建二叉树
        bitTree.build(pre, mid);

        //先序遍历
        bitTree.preTraverse();
        System.out.println();
        //中序遍历
        bitTree.midTraverse();
        System.out.println();
        //后序遍历
        bitTree.postTraverse();
        System.out.println();
        //广度优先遍历
        bitTree.BFS();
    }
}

运行结果为:
A B E K L F D H J
K E L B F A H D J
K L E F B H J D A
A B D E F H J K L

红 - 黑树和 B+树? 红黑树是一种自平衡二叉查找树,由 Rudolf Bayer 发明,在 1978 年被 Leo J. Guibas 和 Robert Sedgewick 改称为“红黑树”。它的特点包括每个节点非红即黑;根节点是黑色;每个叶子节点都是黑色的空节点;如果一个节点是红色的,那么它的两个子节点都是黑色;从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点。在 Java 集合框架中,很多部分如 HashMap、TreeMap、TreeSet 等都有红黑树的应用。 阅读详情

相关推荐

Diffusion Model进阶解析:从SDE到概率流ODE的连续化生成建模

本文深入解析了Diffusion Model的连续化生成建模,从离散DDPM和SGM模型引入,阐述了采用随机微分方程(SDE)统一视角的必要性与优势。文章详细拆解了SDE的构成,揭示了其如何统一描述扩散过程,并重点介绍了逆向SDE与确定性的概率流ODE,后者为高效、确定的图像生成提供了理论基础。最后,文章对比了朗之万动力学、数值SDE求解器和数值ODE求解器(如DPM-Solver)等主流采样方法的实战应用与选择策略。

weixin_29099217的博客 437

Java数据结构-树详解(两万字)

Java数据结构-树详解(两万字)

Android应用开发工程师 3996

生态位宽度计算&可视化展示(R语言)

物种的生态位越宽,该物种的特化程度就越小,倾向于泛化种(generalist species);物种的生态位越窄,倾向于是一个特化种(specialists species)。生态位宽度是指物种(或其它生物单位)在群落中所利用的各种不同资源的总和。本篇所使用为生态位宽度指数即**Levins的生态位宽度指数。

weixin_53705272的博客 4435

深入理解Java数据结构:树

在计算机科学中,树是一种重要的数据结构,具有广泛的应用。它是一种非线性的数据结构,由节点和边组成,可以用来表示层次关系、组织结构、排序等。本文将深入介绍树的基本概念、常见的树结构以及它们在Java编程中的应用。树作为一种重要的数据结构,在计算机科学中具有广泛的应用。通过了解树的基本概念、常见的树结构以及它们在Java编程中的应用,我们可以更好地理解和应用树结构来解决实际问题。合理选择和使用树结构,能够提高程序的效率和性能,实现更加高效的数据组织和操作。

Hhzzy99的博客 4202

CentOS7无网环境实战:MySQL8.0完整离线安装与避坑指南(附依赖包下载)

本文详细介绍了在CentOS7无网环境下MySQL8.0的完整离线安装流程,包括依赖包获取、系统预处理、MySQL二进制安装、服务配置与优化等关键步骤。特别针对离线安装的特殊需求,提供了从依赖包下载到服务调优的全链路解决方案,帮助用户在企业内网或隔离环境中高效部署MySQL数据库。

bush的博客 177

【OWL部署】Manus又一开源平替OWL真的很好用吗?手把手带你部署并运行你的AI助手OWL(对接Qwen、硅基流动接口)

本文介绍了通用人工智能OWL的部署及国内接口对接,全篇干货满满,手把手教学。

MosuoLc的博客 4047

Java数据结构—树

java、数据结构、树

Green_756的博客 4310

基于分位数回归的静态CoVaR计算 案例与代码

原文链接:https://bbs.pinggu.org/thread-7925441-1-1.html 一、静态CoVaR模型介绍 二、资料简介 实现对相关期刊论文进行论文重现,解决实证分析中的技术操作问题。里面包含了每一步详细的步骤,可以方便的利用这个手册解决大部分利用分位数回归计算静态CoVaR的论文的模型实现问题。即从数据下载到模型实现一整条操作步骤。 关键词:【分位数回归】【Co...

ChenQihome9的博客 7506

Java数据结构-树

Java树

qq_51938362的博客 4092

爆破shadow文件密码脚本(完成版)

由于添加了一个for循环,再稍作修改,让password not found!print(f"Trying password:")显示爆破的密码和过程。将代码中的password="123456"替换成下面代码。line.strip()函数首尾去空格。

m0_56578216的博客 772

FPGA电路设计2——芯片原理图绘制

FPGA板卡设计要点:1. 引脚分配遵循电平标准分组原则,需通过预编译验证;2. 电源设计需满足上电时序要求并合理估算功耗;3. 最小系统包含配置Bank(Bank0)、通用I/O Bank(HRBank)、高性能Bank(HPBank)和高速收发器Bank(MGT/GTX)。其中Bank0负责关键配置功能,包括模式选择(支持SPI/BPI/JTAG等5种配置方式)、JTAG调试接口和系统监控引脚,其电压选择(CFGBVS_0)必须与VCCO_0电压匹配。

在读研究生,FPGA电路设计与功能开发。 1245

【推荐】Java数据结构Tree两万字详解

1.n个结点的二叉链表中含有n+1 【公式 2n-(n-1)=n+1】 个空指针域。利用二叉链表中的空指针域,存放指向该结点在某种遍历次序下的前驱和后继结点的指针(这种附加的指针称为"线索")2.这种加上了线索的二叉链表称为线索链表,相应的二叉树称为线索二叉树(Threaded BinaryTree)。根据线索性质的不同,线索二叉树可分为前序线索二叉树、中序线索二叉树和后序线索二叉树三种3.一个结点的前一个结点,称为前驱结点;一个结点的后一个结点,称为后继结点1)给定n个权值作为n个叶子结点。

优秀技术文章收录 2369

181、LLC谐振变换器的PCB设计实战(文件归档)

PCB设计实战经验总结:LLC谐振变换器的关键要点 本文通过实际案例总结了LLC谐振变换器PCB设计中的核心经验和常见误区。重点包括: 文件命名规范(项目代号_板卡类型_版本号_日期格式) 四层板标准层叠结构设计要点 谐振回路走线原则(宽度、长度控制) 地线处理技巧(功率地/控制地隔离) 散热设计注意事项(MOSFET过孔阵列、变压器布局) 完整的文件归档清单(Gerber、钻孔、装配图等) 作者特别强调,良好的设计归档习惯能显著降低生产问题概率,建议采用双重备份机制。文中多个真实案例(如谐振频率偏移、EM

Jack010169的博客 45

【Java数据结构】二叉树到底是什么品种的树?以及二叉树有哪些基操

【Java数据结构】二叉树到底是什么树?以及二叉树有哪些基操树型结构概念树的表示形式树的应用二叉树(重头戏)概念二叉树的基本形态两种特殊的二叉树二叉树的性质三级目录 树型结构 概念 树的表示形式 树的应用 二叉树(重头戏) 概念 二叉树的基本形态 两种特殊的二叉树 二叉树的性质 三级目录 ...

DerrickWestbrook的博客 1004

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

索引选择的艺术:MySQL为何青睐B+树?

我们知道MySQL数据库InnoDB引擎索引的数据结构是B+树,那他为什么不用红黑树,不用B树呢?用B+树的优点在哪里?解决了些什么问题? 下面将以这几个疑问点为中心记录一下MySQL选用B+树的原因。

云泽的博客 1492

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

【恋上数据结构】MySQL的索引底层为何使用 B+树?

总体来说,如果你想转行从事程序员的工作,Java开发一定可以作为你的第一选择。但是不管你选择什么编程语言,提升自己的硬件实力才是拿高薪的唯一手段。如果你以这份学习路线来学习,你会有一个比较系统化的知识网络,也不至于把知识学习得很零散。我个人是完全不建议刚开始就看《Java编程思想》、《Java核心技术》这些书籍,看完你肯定会放弃学习。建议可以看一些视频来学习,当自己能上手再买这些书看又是非常有收获的事了。《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

2401_84408291的博客 694

【TreeSet是什么数据结构?MySQL是什么树?Oracle呢?】

【TreeSet是什么数据结构?MySQL是什么树?Oracle呢?】

学无止境 795

为什么MySQL数据库索引选择使用B+树?

甜菜波波 为什么MySQL数据库索引选择使用B+树? 在进一步分析为什么MySQL数据库索引选择使用B+树之前,我相信很多小伙伴对数据结构中的树还是有些许模糊的,因此我们由浅入深一步步探讨树的演进过程,在一步步引出B树以及为什么MySQL数据库索引选择使用B+树! 学过数据结构的一般对最基础的树都有所认识,因此我们就从与我们主题更为相近的二叉查找树开始。 一、二叉查找树 (1)二叉树简介...

cxu123321的博客 351

【数据结构】初入数据结构的树(Tree)以及Java代码实现(一)

初入数据结构的树(Tree)以及Java代码实现 树的定义 为什么叫树? 树型结构的元素具有一对多关系 树的定义 树的一些基本概念 树的结点 后代,祖先 子树、空树 树的度与高(深度),结点的度与层次 有序树,无序树和森林 树的三种形式的Java代码实现 树的定义(Tree) 为什么叫树? 为什么叫树呢?因为将具有一对多关系的集合中的元素安装上图中的逻辑结构存储,整个存储形...

长路漫漫的歇脚处 2929

什么是树?多种树结构详解

树是由零个或多个结点组成的具有层级关系的数据结构。当树的结点数量等于零时,称为空树。当树的结点数量大于零时,定义以下术语:根结点、叶结点、父结点、子结点、子树。树中有一个唯一的根结点。每个结点有零个或多个子结点,没有子结点的结点称为叶结点。根结点没有父结点,除了根结点以外的每个结点有且只有一个父结点。父结点和子结点是相对关系,甲结点是乙结点的父结点等价于乙结点是甲结点的子结点。对于父结点而言,以子结点为根结点的树称为父结点的子树。

2301_76166241的博客 1429

java建立树_java – 如何创建一个树?

我有一个文本文件,其内容如下:a.b.c.da.ca.da.x.y.za.x.y.aa.x.y.ba.subtree我想把它变成一棵树:a/ / \ \ \b c d x subtree| |c y| / | \d z a b编辑:具有两个节点的a.x.y.a路径需要被...

weixin_35944439的博客 989

MySQL的索引结构为什么使用B+树?

前言 在MySQL中,无论是Innodb还是MyIsam,都使用了B+树作索引结构(这里不考虑hash等其他索引)。本文将从最普通的二叉查找树开始,逐步说明各种树解决的问题以及面临的新问题,从而说明MySQL为什么选择B+树作为索引结构。 目录 一、二叉查找树(BST):不平衡 二、平衡二叉树(AVL):旋转耗时 三、红黑树:树太高 四、B树:为磁盘而生 五、B+树 六、感受B+树的威力 七、总结 一、二叉查找树(BST):不平衡 二叉查找树(BST,Binary Search Tre

wzl1217333452的博客 275

数据结构(AVL树)啥树?自平衡?你懂吗?看这个就懂了

在计算机科学中,AVL 树以其两位苏联发明家Georgy Adelson-Velsky和 Evgenii Landis的名字命名,他们在 1962 年的论文“信息组织算法”中发表了它。它是一种自平衡二叉搜索树(BST),这是发明的第一个这样的数据结构。

zyh_Jan22的博客 1420
上一篇: Java 进阶:多线程2
下一篇: Java内存区域详解(程序计数器、Java 虚拟机栈、本地方法栈、堆、方法区、运行时常量池、直接内存)
JavaCaiy
博客等级 码龄6年 1万+粉丝 95原创
评论 8
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值