首页 > 其他分享 >树形结构构建的两种方式

树形结构构建的两种方式

时间:2024-09-13 17:23:21浏览次数:11  
标签:city 两种 递归 城市 树形 构建 baseMap 节点

树形结构构建的两种方式

树形结构(Tree Structure)是一种常用的数据结构,用于表示具有层次关系的数据集。树形结构由节点(Nodes)组成,这些节点通过边(Edges)相互连接。每个节点可以有零个或多个子节点,但只有一个父节点(除了根节点外)。

一,树形结构的基本概念

  1. 节点(Node)
    • 每个树的组成部分,可以包含数据和其他信息。
    • 每个节点可以有零个或多个子节点。
  2. 根节点(Root Node)
    • 树的顶部节点,没有父节点。
    • 整棵树的起点。
  3. 子节点(Child Node)
    • 每个节点可以拥有一个或多个子节点。
    • 子节点是从父节点延伸出来的。
  4. 父节点(Parent Node)
    • 每个节点(除了根节点)都有一个直接的父节点。
    • 父节点是子节点的直接上级节点。
  5. 叶子节点(Leaf Node)
    • 没有子节点的节点。
    • 位于树的最底层。
  6. 路径(Path)
    • 从一个节点到另一个节点的一系列连续的边。
  7. 深度(Depth)
    • 一个节点到根节点的路径长度。
    • 根节点的深度为 0。
  8. 高度(Height)
    • 树的高度是指从根节点到最远叶子节点的最长路径长度。
    • 树的高度至少为 0(仅包含根节点的树)。

二,使用场景

这种树形结构在多种应用场景中都非常有用,例如:

  1. 行政区域划分
    • 将省份、城市、区县等组织成树形结构,便于管理和查询。
  2. 组织结构
    • 公司内部的部门和职位关系,可以表示为树形结构。
  3. 文件系统
    • 计算机文件系统的目录结构就是一个典型的树形结构。
  4. 产品分类
    • 电子商务网站中的商品分类通常也是树形结构。
  5. 权限管理
    • 用户权限和角色管理中,权限和角色之间的关系可以用树形结构表示。
  6. 菜单导航
    • 网站或应用程序中的多级菜单结构。

三,简单树形结构的创建方式

这里我使用省市县为代表来进行代码实现

1.递归

——(不太推荐)

递归的思路是从顶级节点开始,不断寻找其子节点,并将这些子节点递归地构建到对应的父节点下。

以下是递归版本的代码实现:

@GetMapping("/cityTree") // 将该方法映射为 HTTP GET 请求,访问路径为 /cityTree
public List<City> cityTree() {

    // 从 cityService 中获取所有城市的列表
    List<City> list = cityService.list();

    // 创建一个 HashMap,用于快速查找城市对象
    HashMap<Integer, City> baseMap = new HashMap<>();

    // 将所有城市对象按 ID 存入 baseMap
    for (City city : list) {
        baseMap.put(city.getId(), city);
    }

    // 返回顶级城市列表,通过递归的方式构建子节点
    return buildCityTree(0, baseMap);
}

/**
 * 递归构建城市树形结构
 * 
 * @param parentId 父节点 ID
 * @param baseMap 存储所有城市对象的 Map
 * @return 父节点的子城市列表
 */
private List<City> buildCityTree(int parentId, HashMap<Integer, City> baseMap) {
    List<City> children = new ArrayList<>();

    // 遍历 baseMap 中的所有城市对象
    for (City city : baseMap.values()) {
        // 如果当前城市的父 ID 与传入的 parentId 匹配,则将其视为当前节点的子节点
        if (city.getParentId() == parentId) {
            // 递归构建当前城市的子节点
            city.setChildren(buildCityTree(city.getId(), baseMap));
            // 将当前城市添加到父节点的子城市列表中
            children.add(city);
        }
    }

    return children; // 返回当前节点的子节点列表
}
递归的优缺点

优点:

  1. 代码简洁易读:递归的代码通常更简洁和易于理解,符合人的逻辑思维,直接表达出层级结构的构建过程。
  2. 模块化强:递归将问题分解成子问题,天然符合模块化的设计思想,便于维护和扩展。
  3. 符合层次遍历的自然方式:递归非常适合树形和层次结构的数据处理,代码中直接展现了父子关系的递进性。

缺点:

  1. 内存开销较大:递归调用会占用系统的栈空间,当数据量大或者层级深度过大时,可能导致栈溢出(StackOverflowError)。
  2. 性能问题:递归涉及多次函数调用,调用栈的创建和销毁会带来一定的性能开销,尤其是在大量数据或深度递归时,性能可能不如迭代方式。
  3. 调试困难:递归程序的执行顺序较复杂,调试时不容易跟踪每次调用的状态和变化,容易出错。

递归适用于层次结构明显、数据规模适中的场景。当数据规模较大时,需小心栈空间的限制,可能需要优化或使用其他方式(如显式栈的迭代法)来替代递归。

2.借助Map循环构建

@GetMapping("/cityTree")  // 将该方法映射为 HTTP GET 请求,访问路径为 /cityTree
public List<City> cityTree() {

    // 从 cityService 中获取所有城市的列表
    List<City> list = cityService.list();

    // 创建一个 HashMap,用于存储城市对象,以城市的 ID 作为键,城市对象作为值
    HashMap<Integer, City> baseMap = new HashMap<>();
    // 遍历所有城市,将城市对象存入 baseMap 中
    for (City city : list) {
        baseMap.put(city.getId(), city);
    }

    // 创建一个 List,用于存储最终的城市树形结构
    List<City> cityList = new ArrayList<>();

    // 再次遍历城市列表,将城市按照层级关系组装为树形结构
    for (City city : list) {
        // 判断是否为顶级父类(根节点),即 parentId 为 0
        if (city.getParentId() == 0) {
            cityList.add(city);  // 将顶级城市添加到 cityList 中
            continue;  // 继续下一次循环
        }

        // 如果不是顶级城市,则将其作为子节点添加到对应的父节点下
        City parent = baseMap.get(city.getParentId());  // 获取当前城市的父城市对象
        List<City> children = parent.getChildren();  // 获取父城市的子城市列表

        // 如果子城市列表为空,则初始化子城市列表
        if (children == null) {
            children = new ArrayList<>();
            parent.setChildren(children);  // 将初始化的子城市列表设置回父城市对象中
        }

        // 将当前城市添加到父城市的子城市列表中
        children.add(city);
    }

    // 返回组装好的树形城市列表
    return cityList;
}
功能说明

该方法的主要功能是将一组城市数据根据父子关系组装成树形结构,并返回顶层的城市列表。树形结构意味着每个城市对象可能包含一个子城市列表,这样的层次结构反映了城市间的层级关系(比如省市区的关系)。

实现原理
  1. 数据获取与初始化:首先通过 cityService.list() 获取所有城市的列表,并将所有城市放入 baseMap 中,便于快速通过 ID 查找城市对象。
  2. 城市关系构建:遍历城市列表,根据每个城市的 parentId 判断其是否为顶级节点。如果是顶级节点(parentId == 0),直接添加到 cityList 中;否则,将其作为子节点添加到对应父节点的 children 列表中。
  3. 结果返回:最终返回包含树形结构的顶级城市列表 cityList
优缺点
优点:
  • 高效的父子关系查找:通过 HashMap 快速查找父节点,时间复杂度为 O(1),大大提高了构建树形结构的效率。
  • 结构清晰:代码逻辑分明,容易理解,尤其适合树形结构的构建和展示。
缺点:
  • 内存占用较大:需要额外的 HashMap 来存储城市数据,增加了一定的内存开销。
  • 数据完整性依赖外部数据源:假设 cityService.list() 返回的数据是完整且无误的,未考虑数据异常或缺失的情况,比如缺少某些父节点。
  • 无法处理循环依赖:如果城市数据存在循环依赖(如子节点指向了自己的父节点),可能导致逻辑错误或无限循环,需额外校验数据的合法性。

综合对比

比较维度借助Map循环构建方法递归构建方法
代码简洁度逻辑较多,代码稍显复杂代码简洁,符合自然层次结构
性能较高效,无递归栈调用开销存在递归栈调用开销,较大数据量时性能下降
内存使用需要额外的 HashMap,占用较多内存占用内存较少,但深度过大会消耗栈空间
可维护性逻辑清晰,容易理解和调试递归过程复杂,调试和错误处理较难
安全性无栈溢出风险,适合深层次复杂结构存在栈溢出风险,不适合深度递归

总结

  • 选择递归:如果数据层次结构清晰且层次较少,递归的实现会更简洁直观,易于维护。
  • 选择循环:当面对大数据量和复杂层次的情况时,循环构建方法更为稳定和高效,避免了递归的局限性。

两种方法各有优缺点,选择时应根据实际数据规模、层次深度和对性能的需求综合考虑。

标签:city,两种,递归,城市,树形,构建,baseMap,节点
From: https://blog.csdn.net/m0_56353506/article/details/142215720

相关文章

  • 构建 openEuler Embedded 24.03 LTS (Phytium BSP)
    Ubuntu24.04构建openEulerEmbedded24.03LTS(PhytiumBSP)参考链接:Phytium-OpenEuler-Embedded-BSP-Gitee1介绍本文档介绍如何在Ubuntu24.04上构建openEulerEmbedded24.03LTS(PhytiumBSP)。对计算机配置有要求。2脚本将以下内容复制到新文件oe_phy.sh,添加权......
  • 构建数字化工厂的智能制造-数字化智能制造(82页PPT下载)
    方案介绍:智能制造是指通过信息技术的应用,将传统制造业转变为基于数据和智能化决策的现代化制造方式。它以数字化技术为基础,实现了生产流程的数字化、信息化和自动化。智能制造不仅提升了生产效率和质量,还促进了资源的有效利用和环境保护,实现了绿色生产的目标。构建数字化工厂......
  • jenkins远程启动任务--启用远程触发构建
    一:前言在执行Jenkins的项目构建的时候,一般都是通过web管理界面中的”构建”来执行项目构建操作,但是除此之外我们还可以通过项目配置中的”构建触发器”来触发构建操作,其中”构建触发器”有一种方式是通过配置令牌远程触发项目构建。 二:设置用户token打开当前登录用户设置页面......
  • 电商API接口安全:构建稳固的数字防线
    电子商务的蓬勃发展带来了前所未有的便利,同时也带来了新的安全挑战。API接口作为电商系统的核心组件,其安全性直接关系到企业的数据安全和业务连续性。因此,评估和加固电商API接口的安全性变得尤为重要。电商API接口安全的重要性电商API接口安全不仅涉及到数据的保密性、完整性和......
  • 企业间文件互传方案:构建安全、高效的信息生态圈!
    在日常工作和业务开展过程中,公司内部会产生大量专业资料、图纸、视频、代码等核心数据,需要发送给外部合作伙伴。一般员工会通过IM通讯工具、邮件、FTP等各种方式进行企业间文件互传,但存在一定问题。比如:在使用FTP传输时,会出现大文件传输慢、服务器积累较多数据无法自动清理、传输......
  • 大数据新视界 --大数据大厂之数据治理之道:构建高效大数据治理体系的关键步骤
           ......
  • WPF树形菜单
    WPF保姆级教程怎么实现一个树形菜单 先看一下效果吧:   我们直接通过改造一下原版的TreeView来实现上面这个效果我们先创建一个普通的TreeView代码很简单:<TreeView><TreeViewItemHeader="人事部"/><TreeViewItemHeader="技......
  • rocm Linpack 编译构建系统解析
    0.购买amd显卡,安装rocm1,编译rocHPL下载源码:$gitclone--recursivehttps://github.com/ROCm/rocHPL.git编译:$cdrocHPL/$./install.sh--prefix=${PWD}/../local/会自动gitcloneblit,ucx,opempi,$./mpirun_rochpl-P1-Q1-N8092--NB1282,解析......
  • 2025最新:Java SpringBoot实现房屋租赁管理,三步构建平台,房源实时更新
    ✍✍计算机编程指导师⭐⭐个人介绍:自己非常喜欢研究技术问题!专业做Java、Python、小程序、安卓、大数据、爬虫、Golang、大屏等实战项目。⛽⛽实战项目:有源码或者技术上的问题欢迎在评论区一起讨论交流!⚡⚡Java实战|SpringBoot/SSMPython实战项目|Django微信小程......
  • 从产业区块链到产业数据空间,构建数据价值释放关键引擎 | 林乐博士在2024WAIC产业数据
    7月6日,2024WAIC零数科技产业数据要素流通与应用论坛将于在上海世博中心430会议室成功举办。零数科技创始人兼CEO林乐博士代表主办方致辞,并表示,数据市场已全面启航,数据流通基础设施是构建数据价值释放关键引擎;从产业区块链,到产业数据空间,再到金融数据空间,零数科技正式推出零数可信数......