无向图中寻找指定路径:深度优先遍历算法

刷题记录

1. 节点依赖

背景: 类似于无向图中, 寻找从 起始节点 --> 目标节点 的 线路.

需求: 现在需要从 起始节点 A, 找到所有到 终点 H 的所有路径

A – B : 路径由一个对象构成

public class NodeAssociation {private String leftNodeName;private String rightNodeName;
}

A – B 可以是:

{ leftNodeName = A , rightNodeName = B }或者{ leftNodeName = B , rightNodeName = A }

在这里插入图片描述

找到 A --> E 的所有路径:

以及

找到 A --> D 的所有路径:

【注意】

  1. 可能存在 A --B , B – A 这种干扰项
  2. 可能存在 A – A 这种干扰项
【思路】

深度优先遍历算法解决

这个就是一个典型的无向图中求 路径的问题; 从A 开始找到 A的邻接点列表, 然后选择其中一个结点, 再依次选择其下一个结点, 再找到其邻接点列表,再从列表中选择一个访问, 再访问其下一个结点, 直到找到E为止.具体: 
从 A 开始, A 的邻接列表 [B, C, D]
访问 B , B不是目标节点,继续向下~  B 的邻接列表 [E]
访问 E, E是目标, 存储路径 (A-B-E)然后回退到A, 访问 A的邻接列表的第2个节点 C ..... 
具体代码实现
@Data
public class Solution {// 原始数据private List<NodeAssociation> rawData;// 测试public static void main(String[] args) {Solution solution = new Solution();NodeAssociation nodeAssociation1 = new NodeAssociation("A",  "B");NodeAssociation nodeAssociation2 = new NodeAssociation("A",  "C" );NodeAssociation nodeAssociation3 = new NodeAssociation("A",  "D" );NodeAssociation nodeAssociation4 = new NodeAssociation("B",  "E" );NodeAssociation nodeAssociation5 = new NodeAssociation("E",  "C" );NodeAssociation nodeAssociation6 = new NodeAssociation("E",  "H" );NodeAssociation nodeAssociation7 = new NodeAssociation("D",  "F" );NodeAssociation nodeAssociation8 = new NodeAssociation("H",  "F" );NodeAssociation nodeAssociation9 = new NodeAssociation("D",  "A" ); // 干扰项NodeAssociation nodeAssociation10 = new NodeAssociation("C",  "F" );ArrayList<NodeAssociation> list = new ArrayList<>();list.add(nodeAssociation1);list.add(nodeAssociation2);list.add(nodeAssociation3);list.add(nodeAssociation4);list.add(nodeAssociation5);list.add(nodeAssociation6);list.add(nodeAssociation7);list.add(nodeAssociation8);list.add(nodeAssociation9);list.add(nodeAssociation10);solution.setRawData(list);System.out.println("打印原始数据");for (NodeAssociation rawDatum : solution.rawData) {System.out.println(rawDatum);}solution.find("A", "E", "D");}public void find(String rootNodeName, String target1, String target2) {// 1. 对模型对去重 (A-B) (B-A) --> (A-B);  (A-A)无效节点直接删除List<String> tempList = new ArrayList<>();for (int i = rawData.size() - 1; i >= 0; i--) {NodeAssociation nodeAssociation = rawData.get(i);String leftNodeName = nodeAssociation.getLeftNodeName();String rightNodeName = nodeAssociation.getRightNodeName();// 若有重复,则去重 (A-B) (B-A) --> (A-B)if (tempList.contains(leftNodeName + rightNodeName) || tempList.contains(rightNodeName + leftNodeName)) {rawData.remove(i);continue;}// (A-A) 直接删除if (leftNodeName.equals(rightNodeName)){rawData.remove(i);continue;}tempList.add(leftNodeName + rightNodeName);}// 2. 从索引模型开始遍历List<String> roadList = new ArrayList<>();roadList.add(rootNodeName);List<NodeAssociation> roadNodeList = new ArrayList<>();// 2.1 找到 target1List<List<NodeAssociation>> result1 = new ArrayList<>();dfs(result1, roadList, roadNodeList, rootNodeName, target1);System.out.println("打印  "+rootNodeName+"  -->  "+target1+"结果集:" );for (int i = 0; i < result1.size(); i++) {System.out.println("打印第"+(i+1)+"条路:");for (NodeAssociation nodeAssociation : result1.get(i)) {System.out.println(nodeAssociation);}}// 2.2 找到 target2List<List<NodeAssociation>> result2 = new ArrayList<>();dfs(result2, roadList, roadNodeList, rootNodeName, target2);System.out.println("打印  "+rootNodeName+"  -->  "+target2+"结果集:" );for (int i = 0; i < result2.size(); i++) {System.out.println("打印第"+(i+1)+"条路:");for (NodeAssociation nodeAssociation : result2.get(i)) {System.out.println(nodeAssociation);}}}// 1. 当前走过的路public void dfs(List<List<NodeAssociation>> finalList, List<String> roadList, List<NodeAssociation> roadNodeList, String startName, String targetName) {// 0. 对数据处理 - 放在上一层方法中.// 1. 边界条件: ① 如果 开始节点没有子节点 可以结束 ② 该节点为 目标节点, 则对list进行结果的收取 并返回// 1.1 判断该节点是否为目标节点:if (startName.equals(targetName)) {// 拷贝List<NodeAssociation> result = new ArrayList<>(roadNodeList);// 结果收割finalList.add(result);return;}// 1.2 如果不是目标节点,则需要判断有没有子节点, 从原始数据中List<NodeAssociation> sonNodeList = findSonNodeList(rawData, startName);// 对子节点list进行过滤,过滤掉已经走过的路的结点List<NodeAssociation> collect = sonNodeList.stream().filter((item) -> {String leftNodeName = item.getLeftNodeName();String rightNodeName = item.getRightNodeName();String nextNode = startName.equals(leftNodeName) ? rightNodeName : leftNodeName;return !roadList.contains(nextNode);}).collect(Collectors.toList());if (collect.size() == 0) {return;}// 3. 开始遍历--> 横向遍历for (int i = 0; i < collect.size(); i++) {// 3.1 把当前遍历节点加入路径NodeAssociation curNode = collect.get(i);String leftNodeName = curNode.getLeftNodeName();String rightNodeName = curNode.getRightNodeName();String nextNode = startName.equals(leftNodeName) ? rightNodeName : leftNodeName;roadList.add(nextNode);roadNodeList.add(curNode);// 3.2 开始遍历递归dfs(finalList, roadList, roadNodeList, nextNode, targetName);// 3.3 回溯roadList.remove(roadList.size() - 1);roadNodeList.remove(roadNodeList.size() - 1);}}// 找到子节点listprivate List<NodeAssociation> findSonNodeList(List<NodeAssociation> data, String startName) {return data.stream().filter((item) -> startName.equals(item.getLeftNodeName()) || startName.equals(item.getRightNodeName())).collect(Collectors.toList());}
}

最后的结果:

打印原始数据
NodeAssociation{leftNodeName='A', rightNodeName='B'}
NodeAssociation{leftNodeName='A', rightNodeName='C'}
NodeAssociation{leftNodeName='A', rightNodeName='D'}
NodeAssociation{leftNodeName='B', rightNodeName='E'}
NodeAssociation{leftNodeName='E', rightNodeName='C'}
NodeAssociation{leftNodeName='E', rightNodeName='H'}
NodeAssociation{leftNodeName='D', rightNodeName='F'}
NodeAssociation{leftNodeName='H', rightNodeName='F'}
NodeAssociation{leftNodeName='D', rightNodeName='A'}
NodeAssociation{leftNodeName='C', rightNodeName='F'}
打印  A  -->  E结果集:
打印第1条路:
NodeAssociation{leftNodeName='A', rightNodeName='B'}
NodeAssociation{leftNodeName='B', rightNodeName='E'}
打印第2条路:
NodeAssociation{leftNodeName='A', rightNodeName='C'}
NodeAssociation{leftNodeName='E', rightNodeName='C'}
打印第3条路:
NodeAssociation{leftNodeName='A', rightNodeName='C'}
NodeAssociation{leftNodeName='C', rightNodeName='F'}
NodeAssociation{leftNodeName='H', rightNodeName='F'}
NodeAssociation{leftNodeName='E', rightNodeName='H'}
打印第4条路:
NodeAssociation{leftNodeName='D', rightNodeName='A'}
NodeAssociation{leftNodeName='D', rightNodeName='F'}
NodeAssociation{leftNodeName='H', rightNodeName='F'}
NodeAssociation{leftNodeName='E', rightNodeName='H'}
打印第5条路:
NodeAssociation{leftNodeName='D', rightNodeName='A'}
NodeAssociation{leftNodeName='D', rightNodeName='F'}
NodeAssociation{leftNodeName='C', rightNodeName='F'}
NodeAssociation{leftNodeName='E', rightNodeName='C'}打印  A  -->  D结果集:
打印第1条路:
NodeAssociation{leftNodeName='A', rightNodeName='B'}
NodeAssociation{leftNodeName='B', rightNodeName='E'}
NodeAssociation{leftNodeName='E', rightNodeName='C'}
NodeAssociation{leftNodeName='C', rightNodeName='F'}
NodeAssociation{leftNodeName='D', rightNodeName='F'}
打印第2条路:
NodeAssociation{leftNodeName='A', rightNodeName='B'}
NodeAssociation{leftNodeName='B', rightNodeName='E'}
NodeAssociation{leftNodeName='E', rightNodeName='H'}
NodeAssociation{leftNodeName='H', rightNodeName='F'}
NodeAssociation{leftNodeName='D', rightNodeName='F'}
打印第3条路:
NodeAssociation{leftNodeName='A', rightNodeName='C'}
NodeAssociation{leftNodeName='E', rightNodeName='C'}
NodeAssociation{leftNodeName='E', rightNodeName='H'}
NodeAssociation{leftNodeName='H', rightNodeName='F'}
NodeAssociation{leftNodeName='D', rightNodeName='F'}
打印第4条路:
NodeAssociation{leftNodeName='A', rightNodeName='C'}
NodeAssociation{leftNodeName='C', rightNodeName='F'}
NodeAssociation{leftNodeName='D', rightNodeName='F'}
打印第5条路:
NodeAssociation{leftNodeName='D', rightNodeName='A'}

如果想要得到最短路径, 那么也很简单, 在每次收割结果时,对list做一下判断即可, 每次取最小的list, 便可得到最短路径。

欢迎讨论~~~

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

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

相关文章

Python 爬虫 tiktok关键词搜索用户数据信息 api接口

Tiktok APP API接口 Python 爬虫采集Tiktok数据 采集结果页面如下图&#xff1a; https://www.tiktok.com/search?qwwe&t1706679918408 请求API http://api.xxx.com/tt/search/user?keywordwwe&count10&offset0&tokentest 请求参数 返回示例 联系我们&…

178 折线图-柱形图-饼状图

1.折线图 1、QChart 类继承自 QGraphicsWidget&#xff0c;用于管理图表、图例和轴。2、QValueAxis 类专门用来自定义图表中 X 和 Y 坐标轴。3、QLineSeries 类专门用于折线图&#xff08;曲线&#xff09;的形式展示数据 //.pro QT core gui charts#ifndef WIDGET_H #defi…

Error in onLoad hook: “SyntaxError: Unexpected token u in JSON at position 0“

1.接收页面报错 Error in onLoad hook: "SyntaxError: Unexpected token u in JSON at position 0" Unexpected token u in JSON at position 0 at JSON.parse (<anonymous>) 2.发送页面 &#xff0c;JSON.stringify(item) &#xff0c;将对象转换为 JSO…

前端JS特效第22集:html5音乐旋律自定义交互特效

html5音乐旋律自定义交互特效&#xff0c;先来看看效果&#xff1a; 部分核心的代码如下(全部代码在文章末尾)&#xff1a; <!DOCTYPE html> <html lang"en" > <head> <meta charset"UTF-8"> <title>ChimeTime™</title…

【Python】已解决:xml.parsers.expat.ExpatError: no element found: Line 1, column 0

文章目录 一、分析问题背景二、可能出错的原因三、错误代码示例四、正确代码示例五、注意事项 已解决&#xff1a;xml.parsers.expat.ExpatError: no element found: Line 1, column 0 一、分析问题背景 在使用Python的xml.parsers.expat模块解析XML文件时&#xff0c;有时会…

算法011:最大连续的1的个数

最大连续的1的个数. - 备战技术面试&#xff1f;力扣提供海量技术面试资源&#xff0c;帮助你高效提升编程技能,轻松拿下世界 IT 名企 Dream Offer。https://leetcode.cn/problems/max-consecutive-ones-iii/ 乍一看&#xff0c;这道题很奇怪&#xff0c;什么叫最多翻转k个0&a…

Leetcode3195. 包含所有 1 的最小矩形面积 I

Every day a Leetcode 题目来源&#xff1a;3195. 包含所有 1 的最小矩形面积 I 解法1&#xff1a;遍历 设最左、最右、最上、最下的 1 的行号/列号分别为 left、right、top、bottom&#xff0c;则答案为&#xff1a;(right - left 1) * (bottom - top 1)。 代码&#xf…

新手教学系列——kswapd0 CPU占用100%问题解析与解决

在日常运维中,我们常会遇到一些疑难杂症,其中kswapd0进程CPU占用100%就是一个常见的问题。通常情况下,这个问题是因为内存耗尽,需要使用到swap空间,可以通过调整swap大小或使用比例来控制磁盘读写。然而,今天我要分享的是一个特例,如何在内存并未耗尽且swap使用比例正常…

【STM32项目】基于Stm32搞怪盒子的设计(完整工程资料)

基于stm32搞怪的盒子设计 前言&#xff1a; 最近我看到一个极具创意的搞怪盒子&#xff0c;设计得相当有意思。作为一个热衷于电子DIY的狂热爱好者&#xff0c;怎能错过这样一个有趣的项目呢&#xff1f;于是&#xff0c;我决定亲自动手&#xff0c;设计一个属于自己的、独一无…

Apache Seata分布式事务原理解析探秘

本文来自 Apache Seata官方文档&#xff0c;欢迎访问官网&#xff0c;查看更多深度文章。 本文来自 Apache Seata官方文档&#xff0c;欢迎访问官网&#xff0c;查看更多深度文章。 前言 fescar发布已有时日&#xff0c;分布式事务一直是业界备受关注的领域&#xff0c;fesca…

【carla】ubuntu安装carla环境

我们可以通过查看 CARLA 的 GitHub release 页面来找到最新版本的下载链接。 下载 CARLA 压缩包 访问 CARLA Releases 页面&#xff1a; CARLA Releases on GitHub 查找最新版本&#xff1a; 找到最新的版本&#xff0c;点击下载&#xff0c;第一个压缩包 3. 解压 CARLA 包&…

VMware Workstation Pro 17.5.2 + license key

Workstation Pro是专为Windows操作系统设计的功能强大的虚拟化软件平台,它允许用户在其计算机上创建和运行虚拟机,这使他们能够同时与多个操作系统、应用程序和开发环境一起工作。 Workstation Pro的主要特点之一是其易用性,程序提供了直观的界面,允许用户轻松创建、配置和…

RocketMQ NettyRemotingServer、NettyRemotingClient 实例化、初始化、启动源码解析

&#x1f52d; 嗨&#xff0c;您好 &#x1f44b; 我是 vnjohn&#xff0c;在互联网企业担任后端开发&#xff0c;CSDN 优质创作者 &#x1f4d6; 推荐专栏&#xff1a;Spring、MySQL、Nacos、Java&#xff0c;后续其他专栏会持续优化更新迭代 &#x1f332;文章所在专栏&#…

数学系C++ 类与对象 STL(九)

目录 目录 面向对象&#xff1a;py&#xff0c;c艹&#xff0c;Java都是,但c是面向过程 特征&#xff1a; 对象 内敛成员函数【是啥】&#xff1a; 构造函数和析构函数 构造函数 复制构造函数/拷贝构造函数&#xff1a; 【……】 实参与形参的传递方式&#xff1a;值…

【LeetCode】螺旋矩阵

目录 一、题目二、解法完整代码 一、题目 给你一个 m 行 n 列的矩阵 matrix &#xff0c;请按照 顺时针螺旋顺序 &#xff0c;返回矩阵中的所有元素。 示例 1&#xff1a; 输入&#xff1a;matrix [[1,2,3],[4,5,6],[7,8,9]] 输出&#xff1a;[1,2,3,6,9,8,7,4,5] 示例 2&…

go-redis 封装事件-client封装模型、批量数据处理的导出器设计

一、redis-go的封装实践-client模型 // Copyright 2020 Lingfei Kong <colin404foxmail.com>. All rights reserved. // Use of this source code is governed by a MIT style // license that can be found in the LICENSE file.package storageimport ("context&q…

Halcon 铣刀刀口破损缺陷检测

一 OTSU OTSU&#xff0c;是一种自适应阈值确定的方法,又叫大津法&#xff0c;简称OTSU&#xff0c;是一种基于全局的二值化算法,它是根据图像的灰度特性,将图像分为前景和背景两个部分。当取最佳阈值时&#xff0c;两部分之间的差别应该是最大的&#xff0c;在OTSU算法中所采…

排序 -- 万能测试oj

. - 力扣&#xff08;LeetCode&#xff09; 这道题我们可以使用我们学过的那些常见的排序方法来进行解答 //插入排序 void InsertSort(int* nums, int n) {for (int i 0; i < n-1; i){int end i;int tmp nums[end 1];while (end > 0){if (tmp < nums[end]){nums[…

PyVideoTrans:一款功能全面的视频翻译配音工具!【送源码】

PyVideoTrans是一款功能全面的视频翻译配音工具&#xff0c;专为视频内容创作者设计。它能够将视频中的语言翻译成另一种语言&#xff0c;并自动生成与之匹配的字幕和配音。支持多种语言&#xff0c;包括但不限于中文&#xff08;简繁体&#xff09;、英语、韩语、日语、俄语、…

Wormhole Filters: Caching Your Hash on Persistent Memory——泛读笔记

EuroSys 2024 Paper 论文阅读笔记整理 问题 近似成员关系查询&#xff08;AMQ&#xff09;数据结构可以高效地近似确定元素是否在集合中&#xff0c;例如Bloom滤波器[10]、cuckoo滤波器[23]、quotient滤波器[8]及其变体。但AMQ数据结构的内存消耗随着数据规模的增长而快速增长…