只用一次集合遍历实现树形结构,非递归方式

news2024/11/15 23:53:42

       一般情况下,我们想要实现这种无限层级的树形结构,都是采用递归的方式,但是递归比较占用内存,也容易导致栈溢出,于是只能尝试其它的方法。

        下面采用的方式,只需要一次集合的遍历就可以实现树形的结构。

 先手动编造一个树形结构的数据:

这是一个无序的树形结构数据的 json 格式:

[
  {
    "nodeId" : "700",
    "nodeDesc" : "节点700",
    "parentNodeId" : ""
  },
  {
    "nodeId" : "300",
    "nodeDesc" : "节点300",
    "parentNodeId" : ""
  },
  {
    "nodeId" : "500",
    "nodeDesc" : "节点500",
    "parentNodeId" : ""
  },
  {
    "nodeId" : "100",
    "nodeDesc" : "节点100",
    "parentNodeId" : ""
  },
  {
    "nodeId" : "400",
    "nodeDesc" : "节点400",
    "parentNodeId" : ""
  },
  {
    "nodeId" : "800",
    "nodeDesc" : "节点800",
    "parentNodeId" : ""
  },
  {
    "nodeId" : "200",
    "nodeDesc" : "节点200",
    "parentNodeId" : ""
  },
  {
    "nodeId" : "700-001",
    "nodeDesc" : "节点700-001",
    "parentNodeId" : "700"
  },
  {
    "nodeId" : "700-002",
    "nodeDesc" : "节点700-002",
    "parentNodeId" : "700"
  },
  {
    "nodeId" : "700-003",
    "nodeDesc" : "节点700-003",
    "parentNodeId" : "700"
  },
  {
    "nodeId" : "700-004",
    "nodeDesc" : "节点700-004",
    "parentNodeId" : "700"
  },
  {
    "nodeId" : "700-005",
    "nodeDesc" : "节点700-005",
    "parentNodeId" : "700"
  },
  {
    "nodeId" : "700-006",
    "nodeDesc" : "节点700-006",
    "parentNodeId" : "700"
  },
  {
    "nodeId" : "700-003-002",
    "nodeDesc" : "节点700-003-002",
    "parentNodeId" : "700-003"
  },
  {
    "nodeId" : "700-003-001",
    "nodeDesc" : "节点700-003-001",
    "parentNodeId" : "700-003"
  },
  {
    "nodeId" : "700-003-002-001",
    "nodeDesc" : "节点700-003-002-001",
    "parentNodeId" : "700-003-002"
  },
  {
    "nodeId" : "700-003-002-003",
    "nodeDesc" : "节点700-003-002-003",
    "parentNodeId" : "700-003-002"
  },
  {
    "nodeId" : "700-003-002-002",
    "nodeDesc" : "节点700-003-002-002",
    "parentNodeId" : "700-003-002"
  },
  {
    "nodeId" : "300-001",
    "nodeDesc" : "节点300-001",
    "parentNodeId" : "300"
  },
  {
    "nodeId" : "300-001-001",
    "nodeDesc" : "节点300-001-001",
    "parentNodeId" : "300-001"
  },
  {
    "nodeId" : "300-001-001-001",
    "nodeDesc" : "节点300-001-001-001",
    "parentNodeId" : "300-001-001"
  },
  {
    "nodeId" : "300-001-001-001-001",
    "nodeDesc" : "节点300-001-001-001-001",
    "parentNodeId" : "300-001-001-001"
  },
  {
    "nodeId" : "300-001-001-001-001-001",
    "nodeDesc" : "节点300-001-001-001-001-001",
    "parentNodeId" : "300-001-001-001-001"
  },
  {
    "nodeId" : "500-003",
    "nodeDesc" : "节点500-003",
    "parentNodeId" : "500"
  },
  {
    "nodeId" : "500-001",
    "nodeDesc" : "节点500-001",
    "parentNodeId" : "500"
  },
  {
    "nodeId" : "500-002",
    "nodeDesc" : "节点500-002",
    "parentNodeId" : "500"
  },
  {
    "nodeId" : "500-003-001",
    "nodeDesc" : "节点500-003-001",
    "parentNodeId" : "500-003"
  },
  {
    "nodeId" : "800-001",
    "nodeDesc" : "节点800-001",
    "parentNodeId" : "800"
  },
  {
    "nodeId" : "100-002",
    "nodeDesc" : "节点100-002",
    "parentNodeId" : "100"
  },
  {
    "nodeId" : "100-001",
    "nodeDesc" : "节点100-001",
    "parentNodeId" : "100"
  },
  {
    "nodeId" : "200-001",
    "nodeDesc" : "节点200-001",
    "parentNodeId" : "200"
  },
  {
    "nodeId" : "400-003",
    "nodeDesc" : "节点400-003",
    "parentNodeId" : "400"
  },
  {
    "nodeId" : "400-002",
    "nodeDesc" : "节点400-002",
    "parentNodeId" : "400"
  },
  {
    "nodeId" : "400-001",
    "nodeDesc" : "节点400-001",
    "parentNodeId" : "400"
  },
  {
    "nodeId" : "100-002-002",
    "nodeDesc" : "节点100-002-002",
    "parentNodeId" : "100-002"
  },
  {
    "nodeId" : "100-002-001",
    "nodeDesc" : "节点100-002-001",
    "parentNodeId" : "100-002"
  },
  {
    "nodeId" : "300-001-001-001-001-002",
    "nodeDesc" : "节点300-001-001-001-001-002",
    "parentNodeId" : "300-001-001-001-001"
  },
  {
    "nodeId" : "300-001-001-002",
    "nodeDesc" : "节点300-001-002",
    "parentNodeId" : "300-001"
  }
]

      我是在springBoot项目中测试的,通过前端页面展示数形结构的效果。

      这是后端项目结构,前端使用的 ant-design Vue 版。

   

<template>
  <div>
    <a-tree
      :show-line="true"
      :show-icon="true"
      :tree-data="treeData"
      :replaceFields="{children:'children', title:'nodeDesc', key:'nodeId' }"
      @select="onSelect"
    >
    </a-tree>
  </div>
</template>

<script>

import { queryTreeNodeList } from '@/services/myExample';
import { message } from 'ant-design-vue';

export default {
  name: 'lemonTree',

  data() {
    return {
      treeData: []
    }
  },
  created() {
    queryTreeNodeList().then(response =>{
      console.log(response, '====response====')
      this.treeData = response.data.data
    })
  },
  methods: {
    onSelect(selectedKeys, info) {
      console.log('selected', selectedKeys, info);
      // console.log('nodeDesc', info.selectedNodes[0].data.props.nodeDesc);
      message.info('您点击了:' + info.selectedNodes[0].data.props.nodeDesc);
    }
  }
}
</script>

<style scoped>

</style>

构建树形结构的核心业务代码,都写在了 service 层的这个方法里:

package com.concat.example.service;

import com.alibaba.fastjson2.JSON;
import com.concat.example.entity.LemonTreeEntity;
import org.apache.commons.io.FileUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ResourceUtils;
import org.springframework.util.StringUtils;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class LemonTreeServiceImpl implements LemonTreeService {

    @Override
    public List<LemonTreeEntity> queryAllNodeWithTreeStructure() {
        List<LemonTreeEntity> dataSource = initLemonTree();
        // 如果要得到有顺序树状数据结构,则先进行排序操作,并且后面可以通过循环这个有序的集合组装最终的树状结构的数据;
        List<LemonTreeEntity> lemonTreeNodeList = dataSource.stream().sorted(Comparator.comparing(LemonTreeEntity::getNodeId)).collect(Collectors.toList());

        // 建立每个节点的 map 映射,方便后面快速查找到对应的节点数据;
        Map<String, LemonTreeEntity> lemonTreeNodeMap = new HashMap<>();
        lemonTreeNodeList.stream().forEach(lemonTreeEntity -> {
            String nodeId = lemonTreeEntity.getNodeId();
            lemonTreeNodeMap.put(nodeId, lemonTreeEntity);
        });


        // 结果集;
        List<LemonTreeEntity> lemonTreeResult = new ArrayList<>();

        // 循环这个有序的集合,组装最终的树状结构的数据;
        lemonTreeNodeList.stream().forEach(lemonTreeEntity -> {
            String parentNodeId = lemonTreeEntity.getParentNodeId();
            if (StringUtils.isEmpty(parentNodeId)) {
                // 说明是树的根节点,直接放在集合中;
                lemonTreeResult.add(lemonTreeEntity);
            } else {
                // 其它都是子节点,需要将每个子节点放在对应的父节点的孩子集合中。
                LemonTreeEntity parentTreeNodeEntity = lemonTreeNodeMap.get(parentNodeId);
                List<LemonTreeEntity> children = parentTreeNodeEntity.getChildren();
                if (children == null) {
                    children = new ArrayList<>();
                    parentTreeNodeEntity.setChildren(children);
                }
                children.add(lemonTreeEntity);
            }
        });

//        String json = JSON.toJSONString(lemonTreeResult);
//        System.out.println("json = " + json);
        return lemonTreeResult;
    }

    private List<LemonTreeEntity> initLemonTree() {
        File file = null;
        try {
            file = ResourceUtils.getFile("classpath:lemon_tree.json");
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        }
        String json = null;
        try {
            json = FileUtils.readFileToString(file, "UTF-8");
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        System.out.println("json = " + json);
        List<LemonTreeEntity> lemonTreeEntityList = JSON.parseArray(json, LemonTreeEntity.class);
        System.out.println("lemonTreeEntityList = " + lemonTreeEntityList);

        return lemonTreeEntityList;
    }
}
package com.concat.example.entity;

import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;

@Data
@JsonInclude(JsonInclude.Include.NON_EMPTY)
@NoArgsConstructor
public class LemonTreeEntity {

    private String nodeId;

    private String nodeDesc;

    private String parentNodeId;

    private List<LemonTreeEntity> children;

}

 Web项目其它相关:

package com.concat.example.vo;

import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import java.io.Serializable;

@Data
@Accessors(chain = true)
@NoArgsConstructor
public class MyResponseEntity<T> implements Serializable {

    private String code;

    private String message;

    private T data;

}
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.3.6.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.concat.example</groupId>
	<artifactId>spring-initialize-template</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>spring-initialize-template</name>
	<description>Demo project for Spring Boot</description>
	<properties>
		<java.version>8</java.version>
	</properties>
	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<optional>true</optional>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>commons-io</groupId>
			<artifactId>commons-io</artifactId>
			<version>2.11.0</version>
		</dependency>

		<!-- 反序列化json字符串 -->
		<dependency>
			<groupId>com.alibaba.fastjson2</groupId>
			<artifactId>fastjson2</artifactId>
			<version>2.0.14</version>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Spring Boot 中的 @RabbitListener 注解是什么,原理,如何使用

Spring Boot 中的 RabbitListener 注解是什么&#xff0c;原理&#xff0c;如何使用 在 RabbitMQ 中&#xff0c;消息的接收需要通过监听队列来实现。在 Spring Boot 应用程序中&#xff0c;可以使用 RabbitListener 注解来监听队列&#xff0c;并在接收到消息时执行指定的方法…

Java实现OpenAI模型训练

本文章介绍如何用java实现OpenAI模型训练&#xff0c;仅供参考 提前准备工作 OpenAI KEY&#xff0c;获取方式可自行百度需要自备VPN 或 使用国外服务器转发需要训练的数据集&#xff0c;文章格式要求为JSONL&#xff0c;格式内容详见下图&#xff08;尽量不要低于500个问答&…

消息模块的数据模型设计

目录 一、创建POJO映射类 1. message集合 2. message_ref集合 二、MongoDB的联合查询 MessageRef&#xff1a;保存消息接收人相关信息&#xff0c;接收人ID、消息已读未读、消息是否最新接收。 在 MongoDB 里面我们不需要预先去创建集合&#xff0c;只要我们往 MongoDB 里…

Linux常用命令——finger命令

在线Linux命令查询工具 finger 用于查找并显示用户信息 补充说明 finger命令用于查找并显示用户信息。包括本地与远端主机的用户皆可&#xff0c;帐号名称没有大小写的差别。单独执行finger指令&#xff0c;它会显示本地主机现在所有的用户的登陆信息&#xff0c;包括帐号名…

Layout-静态模板结构搭建、字体图标引入、一级导航渲染、吸顶导航交互实现、Pinia优化重复请求【小兔鲜Vue3】

Layout-静态模板结构搭建 Layout模块静态模板搭建 LayoutNav.vue <script setup></script><template><nav class"app-topnav"><div class"container"><ul><template v-if"true"><li><a h…

鲸鱼算法WOA优化VMD参数,最小包络熵、样本熵、信息熵、排列熵(适应度函数可自行选择,一键修改)包含MATLAB源代码...

鲸鱼优化算法(Whale optimization algorithm, WOA)是Mirjalili根据座头鲸的捕食行为而提出来的&#xff0c;算法对座头鲸的狩猎行为进行模仿&#xff0c;通过对猎物的寻找&#xff0c;然后攻击进行觅食&#xff0c;以此来达到优化的目的&#xff0c;已有很多学者将算法用于实际…

【C/C++实现进程间通信 二】消息队列

文章目录 前情回顾思路源码Publisher.cppSubscriber.cpp 效果 前情回顾 上一期已经讲解过了进程的相关概念以及进程间通信的实现原理&#xff0c;下面仅展示消息传递机制实现1进程间通信的相关代码。 思路 /*本项目主要用于以消息传递机制的方式进行进程间通信的测试。1.主要…

很荣幸与屈晗煜在 GitLink 编程夏令营(GLCC)活动中协作

作为一名软件工程师&#xff0c;天然有着追求代码质量的执念。相信很多人对代码的优雅、质量有着自己的认识&#xff0c;业界也有不少的共识&#xff0c;其中有一条我认为是非常重要的——代码可测试。 作为一名研发&#xff0c;只关注功能可测&#xff08;容易测&#xff09;是…

BUUCTF old-fashion 1

题目描述&#xff1a; 密文&#xff1a; Os drnuzearyuwn, y jtkjzoztzoes douwlr oj y ilzwex eq lsdexosa kn pwodw tsozj eq ufyoszlbz yrl rlufydlx pozw douwlrzlbz, ydderxosa ze y rlatfyr jnjzli; mjy gfbmw vla xy wbfnsy symmyew (mjy vrwm qrvvrf), hlbew rd symmy…

多元回归预测 | Matlab基于鲸鱼算法(WOA)优化混合核极限学习机HKELM回归预测, WOA-HKELM数据回归预测,多变量输入模型

文章目录 效果一览文章概述部分源码参考资料效果一览 文章概述 多元回归预测 | Matlab基于鲸鱼算法(WOA)优化混合核极限学习机HKELM回归预测, WOA-HKELM数据回归预测,多变量输入模型 评价指标包括:MAE、RMSE和R2等,代码质量极高,方便学习和替换数据。要求2018版本及以上。 …

【软考程序员学习笔记】——数据结构与算法基础

目录 &#x1f34a;一、数据结构概念和分类 &#x1f34a;二、数组特点&存储方式 &#x1f34a;三、矩阵 特殊矩阵 非特殊矩阵 &#x1f34a;四、栈和队列 &#x1f34a; 五、二叉树的性质 &#x1f34a;六、二叉树的遍历 (1)前序遍历(先根遍历&#xff0c;先序遍历…

《MySQL》什么是数据库

文章目录 数据库的理解MySQL的架构SQL语句分类存储引擎 数据库的理解 我们所下的数据库软件(如MySQL)其实是中间件。如何理解呢&#xff0c;如图&#xff1a; 我们用户通过MySQL对数据进行管理。 mysql #客户端程序 mysqld #服务端程序&#xff0c;再修改配置后需要重新启动…

【MySQL】在Linux终端上使用MySQL的简单介绍

本文仅供学习参考&#xff01; MySQL是一个开源的跨平台关系数据库管理系统&#xff08;RDBMS&#xff09;。MySQL使用标准查询语言&#xff08;SQL&#xff09;与MySQL软件进行通信。 数据库管理员和开发人员通过运行语句与 RDBMS 交互&#xff0c;这些语句在数据库管理中称为…

前端Vue自定义登录界面切换tabs 账号登录验证码登录模版 支持手机号校验邮箱校验验证码发送

前端Vue自定义登录界面切换tabs 账号登录验证码登录模版 支持手机号校验邮箱校验、验证码发送&#xff0c; 下载完整代码请访问uni-app插件市场地址&#xff1a;https://ext.dcloud.net.cn/plugin?id13298 效果图如下&#xff1a; # cc-loginTabs #### 使用方法 使用方法 …

Spring Boot中@RabbitHandler注解的介绍、原理和使用

Spring Boot中RabbitHandler注解的介绍、原理和使用 引言 在RabbitMQ中&#xff0c;消息的消费者需要根据不同的消息类型进行不同的处理。在Spring Boot中&#xff0c;我们可以通过RabbitHandler注解来实现这一功能。本文将介绍Spring Boot中RabbitHandler注解的介绍、原理和…

【聚类算法】DBSCAN基于密度聚类

every blog every motto: You can do more than you think. https://blog.csdn.net/weixin_39190382?typeblog 0. 前言 瞬间感觉kmeans不香了&#xff0c;哈哈哈 说明&#xff1a; 该算法不仅能聚类&#xff0c;还能剔除离群点&#xff0c;聚类以后标签为-1的即噪声点&…

滑动折叠效果简单实现

绿色为标题&#xff0c;滑动时始终不会被折叠、不会滑动。红色和黑色会在滑动的时候折叠&#xff0c;先折叠红色&#xff0c;在折叠黑色。 activity_shop_search.xml&#xff1a; <?xml version"1.0" encoding"utf-8"?> <layout xmlns:androi…

css实现元素纵向排列自动换列

块级元素在容器类纵向排列&#xff0c;当达到最大高度后自动换到下一列 <div id"main-div"><div class"item">1 一条内容一条内容一条内容一条内容一条内容一条内容一条内容一条内容一条内容一条内容一条内容一条内容一条内容一条内容一条内容…

王道考研计算机网络第四·章知识点汇总

4.1.1网络层功能概述 4.1.2 SDN基本概念 4.2.1 路由算法和路由协议概述 4.3.1 IP数据报格式 4.3.2 IP数据报分片 4.3.3 IPv4地址 4.3.4 网络地址转换NAT 4.3.5 子网划分和子网掩码 不同子网掩码得到的网络地址可能相同 网络号为B类地址&#xff0c;16位网络号&#xff1b;6位子…

从四个角度全面认识 ChatGPT

传统语言模型是什么样的&#xff1f;ChatGPT 涌现出了哪些新能力&#xff1f;这些能力都是怎么做到的&#xff1f;在 ChatGPT 大模型时代&#xff0c;我们应该怎么做&#xff1f; 当下最引人注目的语言模型 ChatGPT 如火如荼&#xff0c;主要还是因为其能力远远超越了传统模型。…