遍历有向图链路(DFS算法)- 优化版

server/2024/12/22 13:29:59/

在上一节基础上,去除了节点的pre集合,只保留节点next的结合,对数据模型进行了优化,实现思想做了优化。

有向图示例:

在这里插入图片描述

基本思路

  1. 构建有向图数据模型
  2. 校验有向图不能出现回路,即当前节点不能出现在历史链路中
  3. 首先找出有向图的初始节点
  4. 找出有向图的初始链路
  5. 链路是从开始节点,按照顺序累加而形成的
  6. 根据节点的next集合,递归遍历初始链路,进而获取所有链路

数据模型:

  1. 节点数据模型:
java">package com.angel.ocean.domain.dsf;import lombok.Data;
import java.util.List;@Data
public class ChainItem {// 该节点IDprivate Integer id;// 该节点可以到达哪些节点的ID列表private List<Integer> next;public ChainItem(Integer id, List<Integer> next) {this.id = id;this.next = next;}
}
  1. 有向图链路数据模型:
java">package com.angel.ocean.domain.dsf;import java.util.List;public class Chain {// ID链路private List<Integer> chainItemIds;// 是否结束private boolean end = false;public List<Integer> getChainItemIds() {return chainItemIds;}public void setChainItemIds(List<Integer> chainItemIds) {this.chainItemIds = chainItemIds;}public boolean isEnd() {return end;}public void setEnd(boolean end) {this.end = end;}
}

算法实现

java">package com.angel.ocean.utils;import cn.hutool.core.collection.CollUtil;
import com.alibaba.fastjson2.JSON;
import com.angel.ocean.domain.dsf.Chain;
import com.angel.ocean.domain.dsf.ChainItem;
import lombok.extern.slf4j.Slf4j;
import java.util.*;@Slf4j
public class ChainHandlerUtil {/*** 获取所有链路* @param chainItems* @return*/public static List<Chain> getAllChain(List<ChainItem> chainItems) {if (CollUtil.isEmpty(chainItems)) {log.info("ChainHandlerUtil.getAllChain(), chainItems is null");throw new RuntimeException("参数为空");}// 链路数据List<Chain> list = new ArrayList<>();// 1. 获取初始节点List<ChainItem> firstItemList = getFirstItemList(chainItems);if(CollUtil.isEmpty(firstItemList)) {throw new RuntimeException("参数校验失败,不存在初始节点");}// 2. 获取初始链路for (ChainItem chainItem : firstItemList) {List<Integer> chainItemIds = new ArrayList<>();chainItemIds.add(chainItem.getId());Chain chain = new Chain();chain.setChainItemIds(chainItemIds);// 是否为终止链路,终止链路设置为trueif(CollUtil.isEmpty(chainItem.getNext())) {chain.setEnd(true);}list.add(chain);}// 3. 根据初始链路递归出所有链路数据// 是否所有链路都结束了boolean allChainIsEnd = false;while (!allChainIsEnd) {list = chainDataHandler(list, chainItems);allChainIsEnd = true;for (Chain chain : list) {if(!chain.isEnd()) {allChainIsEnd = false;}}}return list;}/*** 获取初始节点列表,不存在于next中的节点就是初始节点* @param chainItems* @return*/private static List<ChainItem> getFirstItemList(List<ChainItem> chainItems) {// 非初始节点集合Set<Integer> nextItemIds = new HashSet<>();for (ChainItem chainItem : chainItems) {if(CollUtil.isNotEmpty(chainItem.getNext())) {nextItemIds.addAll(chainItem.getNext());}}// 初始节点集合List<ChainItem> firstItemIds = new ArrayList<>();for (ChainItem chainItem : chainItems) {if(!nextItemIds.contains(chainItem.getId())) {firstItemIds.add(chainItem);}}return firstItemIds;}/*** 链路数据迭代* @param list* @param chainItems* @return*/private static List<Chain> chainDataHandler(List<Chain> list, List<ChainItem> chainItems) {List<Chain> newList = new ArrayList<>();for (Chain chain: list) {if(chain.isEnd()) {newList.add(chain);continue;}List<Integer> chainItemIds = chain.getChainItemIds();int chainEndItemId = chainItemIds.get(chainItemIds.size() - 1);ChainItem chainEndItem = getChainItemById(chainEndItemId, chainItems);for (Integer id : chainEndItem.getNext()) {// 是否为回路校验if(chainItemIds.contains(id)) {throw new RuntimeException("参数校验失败,链路出现回路");}Chain newChain = new Chain();List<Integer> newChainItemIds = new ArrayList<>();newChainItemIds.addAll(chainItemIds);newChainItemIds.add(id);newChain.setChainItemIds(newChainItemIds);ChainItem nextItem = getChainItemById(id, chainItems);// 是否为终止链路,终止链路设置为trueif(CollUtil.isEmpty(nextItem.getNext())) {newChain.setEnd(true);}newList.add(newChain);}}return newList;}/*** 获取ItemById** @param id* @param chainItems* @return*/private static ChainItem getChainItemById(Integer id, List<ChainItem> chainItems) {for (ChainItem chainItem : chainItems) {if (chainItem.getId().equals(id)) {return chainItem;}}return null;}
}

算法验证

java">public static void main(String[] args) {// 上述有向图可以转换成如下数据List<ChainItem> chainItems = new ArrayList<>();chainItems.add(new ChainItem(1, Arrays.asList(2, 6)));chainItems.add(new ChainItem(2, Arrays.asList(3, 7)));chainItems.add(new ChainItem(3, Arrays.asList(4, 12)));chainItems.add(new ChainItem(4, Arrays.asList(5, 7)));chainItems.add(new ChainItem(5,  null));chainItems.add(new ChainItem(6, Arrays.asList(2)));chainItems.add(new ChainItem(7, Arrays.asList(8)));chainItems.add(new ChainItem(8, Arrays.asList(5)));chainItems.add(new ChainItem(9, Arrays.asList(10, 13)));chainItems.add(new ChainItem(10, Arrays.asList(3)));chainItems.add(new ChainItem(11, Arrays.asList(4)));chainItems.add(new ChainItem(12, Arrays.asList(5, 11)));chainItems.add(new ChainItem(13, Arrays.asList(15, 17)));chainItems.add(new ChainItem(15, Arrays.asList(16)));chainItems.add(new ChainItem(16, Arrays.asList(17)));chainItems.add(new ChainItem(17, null));chainItems.add(new ChainItem(18, null));chainItems.add(new ChainItem(19, Arrays.asList(20)));chainItems.add(new ChainItem(20, null));List<Chain> chains = getAllChain(chainItems);for (Chain chain : chains) {log.info("{}", JSON.toJSONString(chain));}
}

运行结果:

在这里插入图片描述


http://www.ppmy.cn/server/131657.html

相关文章

美团Java一面

美团Java一面 9.24一面&#xff0c;已经寄了 收到的第一个面试&#xff0c;表现很不好 spring bean生命周期 作用域&#xff08;忘完了&#xff09; 为什么用redis缓存 redis和数据库的缓存一致性问题 redis集群下缓存更新不一致问题 aop说一下 arraylist和linkedlist 数据库的…

3D看车如何实现?有哪些功能特点和优势?

3D看车是一种创新的汽车展示方式&#xff0c;它利用三维建模和虚拟现实技术&#xff0c;将汽车以更真实、更立体的形式呈现在消费者面前。 一、3D看车的实现方式 1、三维建模&#xff1a; 通过三维建模技术&#xff0c;按照1:1的比例还原汽车外观&#xff0c;包括车身线条、细…

C#操作SqlServer数据库语句

操作数据库语句 操作数据库语句需要搭配数据库的连接Connection类 和下达SQL命令Command类 1. ExecuteNonQuery ExecuteNonQuery 方法主要用来更新数据。通常使用它来执行Update、Insert和Delete语句&#xff0c;最后执行sql语句的时候可以用一个整形变量来接收&#xff0c;返…

[Linux]文件系统

本文以ext2文件系统进行讲解演示,ext2是一个很老的文件系统,现在并不常见,不过作为示例用来增强对底层的理解是足够的 粗略模型 从操作系统层面来说,一个Linux文件系统有且仅有一个磁盘,操作系统会先对磁盘进行分区,然后在对区进行分组,1个组中有多个内存块,用来存放文件的属性…

【一个简单的JavaScript网页设计案例】

首先&#xff0c;我们需要一些HTML来构建基本的页面结构&#xff0c;接着是一些CSS来美化页面&#xff0c;最后是JavaScript来实现功能。 HTML (index.html) <!DOCTYPE html> <html lang"zh"> <head> <meta charset"UTF-8"> <…

机器学习的四大学派:符号主义学派、贝叶斯学派、连接主义学派与进化仿生学派

目录 前言1. 符号主义学派1.1 含义与理论基础1.2 特点1.3 应用 2. 贝叶斯学派2.1 含义与理论基础2.2 特点2.3 应用 3. 连接主义学派3.1 含义与理论基础3.2 特点3.3 应用 4. 进化仿生学派4.1 含义与理论基础4.2 特点4.3 应用 结语 前言 机器学习作为人工智能的核心技术之一&…

【MySQL】详解binlog和redolog两阶段提交

在 MySQL 的事务执行过程中&#xff0c;binlog 和 redo log&#xff08;重做日志&#xff09;协同工作来确保事务的持久性和数据一致性。MySQL 使用一种称为 【两阶段提交】 的机制来确保这两个日志之间的一致性&#xff0c;以避免在崩溃时出现数据不一致的情况。 在我前面的 博…

众数信科 AI智能体政务服务解决方案——寻知智能笔录系统

政务服务解决方案 寻知智能笔录方案 融合民警口供录入与笔录生成需求 2分钟内生成笔录并提醒错漏 助办案人员二次询问 提升笔录质量和效率 寻知智能笔录系统 众数信科AI智能体 产品亮点 分析、理解行业知识和校验规则 AI实时提醒用户文书需注意部分 全文校验格式、内容…