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

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

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

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

这是一个无序的树形结构数据的 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>

点击下载后端工程

点击下载前端工程

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

windfallsheng

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值