首页 > 编程语言 >Java实现管线拓扑关系连通性分析

Java实现管线拓扑关系连通性分析

时间:2024-06-24 12:54:00浏览次数:14  
标签:Java graph 拓扑 vertex DFS public 搜索 连通性 节点

管线拓扑关系的连通性分析通常涉及图论(Graph Theory)中的概念,特别是无向图(Undirected Graph)的遍历算法,如深度优先搜索(DFS, Depth-First Search)或广度优先搜索(BFS, Breadth-First Search)。

在管线拓扑中,管线可以被视为图的边(Edge),而管线的连接点可以被视为图的节点(Vertex)。连通性分析的目标是确定哪些节点(或管线)是相互连通的。

1.Graph类来表示管线拓扑关系

以下是一个使用Java实现的简单示例,该示例定义了一个Graph类来表示管线拓扑关系,并使用深度优先搜索(DFS)来进行连通性分析。

1.1 定义节点(Vertex)和边(Edge)

由于这个示例关注的是连通性分析,我们不需要显式定义Edge类,但可以通过在Vertex类中存储相邻节点的列表来隐式表示边。

import java.util.ArrayList;  
import java.util.List;  
  
public class Vertex {  
    private int id;  
    private List<Vertex> adjacentVertices;  
  
    public Vertex(int id) {  
        this.id = id;  
        this.adjacentVertices = new ArrayList<>();  
    }  
  
    public int getId() {  
        return id;  
    }  
  
    public void addAdjacentVertex(Vertex vertex) {  
        adjacentVertices.add(vertex);  
    }  
  
    public List<Vertex> getAdjacentVertices() {  
        return adjacentVertices;  
    }  
  
    // 用于DFS的标记,表示是否已访问过  
    private boolean visited;  
  
    public boolean isVisited() {  
        return visited;  
    }  
  
    public void setVisited(boolean visited) {  
        this.visited = visited;  
    }  
}

1.2 定义图(Graph)

import java.util.HashMap;  
import java.util.Map;  
  
public class Graph {  
    private Map<Integer, Vertex> vertices;  
  
    public Graph() {  
        vertices = new HashMap<>();  
    }  
  
    public void addVertex(int id) {  
        Vertex vertex = new Vertex(id);  
        vertices.put(id, vertex);  
    }  
  
    public void addEdge(int fromId, int toId) {  
        Vertex fromVertex = vertices.get(fromId);  
        Vertex toVertex = vertices.get(toId);  
        if (fromVertex == null || toVertex == null) {  
            throw new IllegalArgumentException("Vertex does not exist");  
        }  
        fromVertex.addAdjacentVertex(toVertex);  
        // 在无向图中,需要添加反向边  
        toVertex.addAdjacentVertex(fromVertex);  
    }  
  
    public void dfs(int startId) {  
        Vertex startVertex = vertices.get(startId);  
        if (startVertex == null) {  
            throw new IllegalArgumentException("Start vertex does not exist");  
        }  
        dfsUtil(startVertex);  
    }  
  
    private void dfsUtil(Vertex vertex) {  
        vertex.setVisited(true);  
        System.out.println("Visited vertex: " + vertex.getId());  
  
        for (Vertex adjacentVertex : vertex.getAdjacentVertices()) {  
            if (!adjacentVertex.isVisited()) {  
                dfsUtil(adjacentVertex);  
            }  
        }  
    }  
  
    // 用于测试连通性的方法(例如,打印所有与给定顶点连通的顶点)  
    public void printConnectedComponents(int startId) {  
        // 重置所有顶点的访问状态  
        for (Vertex vertex : vertices.values()) {  
            vertex.setVisited(false);  
        }  
  
        dfs(startId);  
  
        // (这里省略了打印未连通顶点的逻辑,如果需要,可以添加)  
    }  
}

1.3 使用示例

public class Main {  
    public static void main(String[] args) {  
        Graph graph = new Graph();  
  
        // 添加节点  
        graph.addVertex(1);  
        graph.addVertex(2);  
        graph.addVertex(3);  
        graph.addVertex(4);  
  
        // 添加边(管线)  
        graph.addEdge(1, 2);  
        graph.addEdge(2, 3);  
        graph.addEdge(3, 4);  
  
        // 进行连通性分析(从节点1开始)  
        graph.printConnectedComponents(1);  
  
        // 如果需要分析其他连通组件,可以重置访问状态并从其他节点开始DFS  
    }  
}

2.连通性分析的多个连通组件

在上面的示例中,我们只展示了一个简单的连通性分析,它从一个给定的顶点开始并打印了所有与该顶点连通的顶点。然而,在真实的场景中,图可能包含多个不连通的组件。为了找到所有的连通组件,我们需要稍微修改代码以迭代处理所有未访问过的顶点。

下面是一个更完整的示例,它展示了如何找到并打印出图中所有的连通组件:

public class Main {  
    public static void main(String[] args) {  
        Graph graph = new Graph();  
  
        // 添加节点  
        graph.addVertex(1);  
        graph.addVertex(2);  
        graph.addVertex(3);  
        graph.addVertex(4);  
        graph.addVertex(5); // 假设5是一个孤立的节点  
  
        // 添加边(管线)  
        graph.addEdge(1, 2);  
        graph.addEdge(2, 3);  
        graph.addEdge(3, 4);  
  
        // 查找并打印所有连通组件  
        graph.findAllConnectedComponents();  
    }  
}  
  
public class Graph {  
    // ...(之前的Graph类代码保持不变)  
  
    // 添加一个新的方法来查找并打印所有连通组件  
    public void findAllConnectedComponents() {  
        // 标记所有顶点为未访问  
        for (Vertex vertex : vertices.values()) {  
            vertex.setVisited(false);  
        }  
  
        // 遍历所有顶点,对每个未访问的顶点启动DFS  
        for (Vertex vertex : vertices.values()) {  
            if (!vertex.isVisited()) {  
                System.out.println("Connected component starting from vertex " + vertex.getId() + ":");  
                dfsUtil(vertex);  
                System.out.println(); // 打印完一个连通组件后换行  
            }  
        }  
    }  
  
    // ...(之前的Graph类中的其他方法保持不变)  
}

现在,当我们运行Main类时,它会找到并打印出图中所有的连通组件。在这个例子中,我们将看到一个包含顶点1、2、3、4的连通组件,以及一个只包含顶点5的孤立连通组件(如果顶点5没有与其他任何顶点相连的话)。

请注意,这个示例假设图是静态的,并且不会在运行时添加或删除顶点或边。如果我们的应用场景需要在运行时动态地修改图,那么我们可能需要添加额外的逻辑来处理这些变化,并可能需要使用更复杂的数据结构来高效地实现这些操作。

3.实现一个基于邻接列表的图结构(DFS算法)

当我们谈论“管线拓扑关系连通性分析”时,我们通常指的是在一个由节点(比如管线的端点或关键位置)和边(比如实际的管线)组成的图中,找出哪些节点是连通的。在Java中,这可以通过深度优先搜索(DFS)或广度优先搜索(BFS)等图遍历算法来实现。

以下是一个具体的Java代码示例,用于实现一个基于邻接列表的图结构,并使用DFS算法来找出并打印所有的连通组件:

import java.util.*;  
  
class Vertex {  
    int id;  
    boolean visited;  
  
    public Vertex(int id) {  
        this.id = id;  
        this.visited = false;  
    }  
  
    public void setVisited(boolean visited) {  
        this.visited = visited;  
    }  
  
    public boolean isVisited() {  
        return visited;  
    }  
  
    public int getId() {  
        return id;  
    }  
}  
  
class Graph {  
    private Map<Integer, Vertex> vertices;  
    private Map<Vertex, List<Vertex>> adjList;  
  
    public Graph() {  
        vertices = new HashMap<>();  
        adjList = new HashMap<>();  
    }  
  
    public void addVertex(int id) {  
        Vertex vertex = new Vertex(id);  
        vertices.put(id, vertex);  
        adjList.put(vertex, new ArrayList<>());  
    }  
  
    public void addEdge(int src, int dest) {  
        Vertex sourceVertex = vertices.get(src);  
        Vertex destinationVertex = vertices.get(dest);  
  
        if (sourceVertex == null || destinationVertex == null) {  
            System.out.println("Vertex not found. Cannot add edge.");  
            return;  
        }  
  
        adjList.get(sourceVertex).add(destinationVertex);  
        // 如果图是无向的,还需要添加反向边  
        adjList.get(destinationVertex).add(sourceVertex);  
    }  
  
    public void dfs(Vertex vertex) {  
        vertex.setVisited(true);  
        System.out.print(vertex.getId() + " ");  
  
        List<Vertex> neighbors = adjList.get(vertex);  
        for (Vertex neighbor : neighbors) {  
            if (!neighbor.isVisited()) {  
                dfs(neighbor);  
            }  
        }  
    }  
  
    public void findAllConnectedComponents() {  
        // 标记所有顶点为未访问  
        for (Vertex vertex : vertices.values()) {  
            vertex.setVisited(false);  
        }  
  
        // 遍历所有顶点,对每个未访问的顶点启动DFS  
        for (Vertex vertex : vertices.values()) {  
            if (!vertex.isVisited()) {  
                System.out.println("Connected component starting from vertex " + vertex.getId() + ":");  
                dfs(vertex);  
                System.out.println(); // 打印完一个连通组件后换行  
            }  
        }  
    }  
  
    public static void main(String[] args) {  
        Graph graph = new Graph();  
  
        // 添加节点  
        graph.addVertex(1);  
        graph.addVertex(2);  
        graph.addVertex(3);  
        graph.addVertex(4);  
        graph.addVertex(5); // 假设5是一个孤立的节点  
  
        // 添加边(管线)  
        graph.addEdge(1, 2);  
        graph.addEdge(2, 3);  
        graph.addEdge(3, 4);  
  
        // 查找并打印所有连通组件  
        graph.findAllConnectedComponents();  
    }  
}

在这个示例中,Graph类管理了一个Map,用于存储顶点和它们的邻接列表。Vertex类表示图中的每个节点,包含一个id和一个visited标志。addVertex方法用于添加新的顶点,addEdge方法用于在图中添加边。dfs方法实现了深度优先搜索,用于遍历与给定顶点连通的所有节点。findAllConnectedComponents方法用于找到并打印出图中所有的连通组件。

main方法中,我们创建了一个Graph对象,添加了几个节点和边,并调用了findAllConnectedComponents方法来找出并打印所有的连通组件。由于顶点5是孤立的,所以它将作为一个单独的连通组件被打印出来。

4.算法的原理介绍

算法的原理主要基于图的遍历,特别是深度优先搜索(DFS)或广度优先搜索(BFS)算法。以下是针对深度优先搜索(DFS)算法原理的详细解释:

(1)基本思想:

  • 深度优先搜索(DFS)是一种用于遍历或搜索树或图的算法。
  • 它的基本思想是尽可能深地搜索图的分支,直到到达叶节点或无法再深入为止,然后回溯到前一个节点,继续探索其他分支。

(2)实现方式:

  • DFS通常使用递归或栈来实现。
  • 对于树或图的遍历,可以从根节点或任意节点开始,然后沿着某个分支深入搜索,直到达到叶节点或无法再深入为止。
  • 在搜索过程中,需要记录已经访问过的节点,以避免重复访问。

(3)数据结构:

  • DFS在实现过程中通常使用栈(stack)这种数据结构来辅助实现。
  • 在搜索过程中,将当前访问的节点以及从起始节点到该节点的路径上的所有节点都放入栈中。
  • 当搜索到叶节点或无法再深入时,从栈中弹出当前节点,并回溯到上一个节点,继续搜索。

(4)核心思想:

  • 回溯(backtracking):当搜索到叶节点或无法再深入时,需要回溯到上一个节点,继续搜索其他未遍历的分支。满足回溯条件的某个状态的点称为“回溯点”。

(5)时间复杂度:

  • DFS的时间复杂度在最坏情况下为O(n!),其中n为图中节点的数量。然而,在实际应用中,由于图的结构和搜索策略的不同,DFS的时间复杂度可能会有所不同。

(6)应用:

  • DFS在多种场景下都有应用,如拓扑排序、找出图中的所有强连通分支等。
  • 拓扑排序是一种对DAG(有向无环图)的顶点进行排序的算法,它使得对每一条有向边(u, v),均有u(在排序记录中)比v先出现。DFS是实现拓扑排序的一种有效方法。
  • 找出图中的所有强连通分支也是DFS的一个重要应用,它可以帮助我们理解图的连通性结构。

总结来说,深度优先搜索(DFS)算法的原理是通过递归或栈来辅助实现图的遍历,尽可能地深入搜索图的分支,并在无法深入时回溯到上一个节点继续搜索,从而确保图中的每个节点都被访问到。DFS的时间复杂度和应用取决于图的结构和搜索策略的不同。

5.深度优先搜索和广度优先搜索的区别

深度优先搜索(DFS, Depth-First Search)和广度优先搜索(BFS, Breadth-First Search)是两种用于遍历或搜索树或图的算法,它们之间的主要区别在于遍历的顺序和使用的数据结构。

5.1深度优先搜索(DFS)

遍历顺序:DFS尽可能深地搜索图的分支。它沿着树的深度遍历图的节点,尽可能深地搜索图的分支。当节点v的所在边都已被探寻过,搜索将回溯到发现节点v的那条边的起始节点。这一过程一直进行到已发现从源节点可达的所有节点为止。如果还存在未被发现的节点,则选择其中一个作为源节点并重复以上过程,整个进程反复进行直到所有节点都被访问为止。

数据结构:DFS通常使用栈(stack)来实现。在搜索过程中,将当前访问的节点以及从起始节点到该节点的路径上的所有节点都放入栈中。当搜索到叶节点或无法再深入时,从栈中弹出当前节点,并回溯到上一个节点,继续搜索。

5.2广度优先搜索(BFS)

遍历顺序:BFS从根节点(或任意节点)开始,访问所有相邻的节点,然后对每个相邻节点,再访问它们的相邻节点,以此类推。这个过程按照广度(即层次)的顺序进行,直到图中所有可达的节点都被访问到。

数据结构:BFS通常使用队列(queue)来实现。在搜索过程中,将当前访问的节点放入队列中,然后取出队列中的第一个节点进行访问,并将其所有未被访问过的相邻节点放入队列的末尾。这个过程一直进行到队列为空,即所有可达的节点都被访问到为止。

5.3主要区别

(1)遍历顺序:DFS按照深度优先的顺序遍历节点,而BFS按照广度优先的顺序遍历节点。

(2)数据结构:DFS通常使用栈来实现,而BFS通常使用队列来实现。

(3)空间复杂度:在最坏的情况下,DFS和BFS的空间复杂度都可能是O(V),其中V是图中节点的数量。然而,由于DFS使用递归或栈来保存状态,如果图的深度很大,可能会导致栈溢出。而BFS使用队列来保存状态,通常可以处理更大的图。

(4)时间复杂度:DFS和BFS的时间复杂度都取决于图的遍历方式。在无权图中,两者的时间复杂度都是O(V+E),其中V是节点数量,E是边数量。然而,在带权图中,如果使用DFS来实现Dijkstra算法等,时间复杂度可能会更高。

(5)应用:DFS常用于拓扑排序、查找强连通分量等场景,而BFS常用于最短路径问题(如未加权的图)、遍历二叉树或图等场景。

6. DFS和BFS简介

当然可以,以下是关于深度优先搜索(DFS)和广度优先搜索(BFS)的详细介绍:

6.1深度优先搜索(DFS)

(1)定义

深度优先搜索(DFS)是一种用于遍历或搜索树或图的算法。它从根节点(或任意节点)开始,沿着一条路径不断访问邻接节点,直到没有未访问的邻接节点为止,然后回溯到上一个节点,继续访问其他邻接节点。

(2)实现方式

  • 递归实现:DFS可以通过递归函数来实现,每次递归调用都会深入到一个新的分支进行搜索。
  • 栈实现:另一种实现DFS的方法是使用栈(stack)。首先将根节点压入栈中,然后不断从栈顶取出节点进行访问,并将其所有未访问的邻接节点压入栈中。

(3)算法特点

  • 回溯:当搜索到叶节点或无法再深入时,DFS会回溯到上一个节点,继续搜索其他未遍历的分支。
  • 空间复杂度:在最坏的情况下,DFS的空间复杂度为O(V),其中V是图中节点的数量。
  • 时间复杂度:DFS的时间复杂度依赖于具体的图和搜索策略,但在无权图中,其时间复杂度通常为O(V+E),其中E是边的数量。

(4)应用场景

  • 图的连通性检查
  • 生成树的构造
  • 解决迷宫问题
  • 树的遍历(如二叉树、多叉树等)

6.2广度优先搜索(BFS)

(1)定义

广度优先搜索(BFS)是一种从根(或任意节点)开始并探索最近的节点的算法。它首先访问所有相邻的节点,然后对每个相邻节点,再访问它们的相邻节点,这样一层一层地进行。

(2)实现方式

BFS使用队列(queue)数据结构来保存信息。首先将根节点放入队列中,然后不断从队列中取出节点进行访问,并将其所有未被访问过的相邻节点加入队列的末尾。

(3)算法特点

  • 层次遍历:BFS按照层次遍历的顺序访问节点,首先访问根节点的所有邻接节点,然后访问这些节点的所有邻接节点,依此类推。
  • 空间复杂度:在最坏的情况下,BFS的空间复杂度为O(V),其中V是图中节点的数量。
  • 时间复杂度:在无权图中,BFS的时间复杂度通常为O(V+E),其中E是边的数量。

(4)应用场景

  • 最短路径问题(如未加权的图)
  • 层次遍历(如二叉树、多叉树等)
  • 图的连通性检查
  • 网络爬虫(在网页搜索中,BFS被用来遍历网页之间的链接)

6.3总结

DFS和BFS是两种常见的图遍历算法,它们各有特点和应用场景。DFS适用于深度探索,而BFS则更适用于广度探索。在实际应用中,我们需要根据问题的特性来选择最合适的算法。

标签:Java,graph,拓扑,vertex,DFS,public,搜索,连通性,节点
From: https://www.cnblogs.com/TS86/p/18264824

相关文章

  • Java Script-使用DOM编程实现移动坦克
    要求:实现:将坦克图片放在页面上:<imgid="mytank"src="./img/right.png"/>在css中设置坦克的初始位置以及页面背景:<styletype="text/css">    input{font-size:26px;margin-top:20px;}    body{background-image:url("./img/gra......
  • 七、若依--P17--P18【黑马程序员Java最新AI+若依框架项目开发新方案视频教程,基于RuoYi
    学习视频【黑马程序员Java最新AI+若依框架项目开发新方案视频教程,基于RuoYi-Vue3前后端分离版本,从前端到后端再到AI智能化应用全通关】https://www.bilibili.com/video/BV1pf421B71v/?p=6&share_source=copy_web&vd_source=3949d51b57b2891ea14d6e51c792bef6二次开发P17:新......
  • JavaScript第十二讲:DOM编程“创建,删除,替换,插入节点”
    目录1.创建节点2.删除节点3.替换节点4.插入节点使用appendChild()使用insertBefore()深入解析与注意事项1.创建节点在HTMLDOM中,我们通常使用JavaScript的document.createElement()方法来创建元素节点,使用document.createTextNode()方法来创建文本节点。示例......
  • 【数据结构与算法】拓扑排序,关键活动,关键路径 详解
    拓扑排序算法booltopologicalSort(){ stack<int>stk; intid[N]; intcnt=0; for(inti=1;i<=n;i++){ if(!inDeg[i]){ stk.push(i); } id[i]=inDeg[i]; } while(stk.size()){ intt=stk.top(); stk.pop(); cout<<t<......
  • SSM-学情分析系统-56772(免费领源码+开发文档)可做计算机毕业设计JAVA、PHP、爬虫、APP
    学情分析系统摘 要随着科学技术的飞速发展,各行各业都在努力与现代先进技术接轨,通过科技手段提高自身的优势;对于学情分析系统当然也不能排除在外,随着网络技术的不断成熟,带动了学情分析系统,它彻底改变了过去传统的管理方式,不仅使服务管理难度变低了,还提升了管理的灵活性。这......
  • 基于SpringBoot的高校大学生学科竞赛管理系统+53135(免费领源码)可做计算机毕业设计JAVA
    springboot高校大学生学科竞赛管理系统的设计与实现摘 要随着互联网趋势的到来,各行各业都在考虑利用互联网将自己推广出去,最好方式就是建立自己的互联网系统,并对其进行维护和管理。在现实运用中,应用软件的工作规则和开发步骤,采用Java技术建设高校大学生学科竞赛管理系统。......
  • java java.nio.channels.ClosedChannelException
    java.nio.channels.ClosedChannelException报错信息"java.nio.channels.ClosedChannelException"表示尝试在一个已经关闭的通道上进行操作。在JavaNIO中,通道(Channel)表示一个可以进行IO操作的对象,例如读取或写入数据。当你尝试在一个已经被关闭的通道上进行读取、写入或者其他......
  • Java大文件上传、分片上传、多文件上传、断点续传、上传文件minio、分片上传minio等解
    上传说明    文件上传花样百出,根据不同场景使用不同方案进行实现尤为必要。通常开发过程中,文件较小,直接将文件转化为字节流上传到服务器,但是文件较大时,用普通的方法上传,显然效果不是很好,当文件上传一半中断再次上传时,发现需要重新开始,这种体验不是很爽,下面介绍几种好一......
  • java的输入流FileInput Stream类
    一、定义使用InputStream类的FileInputStream子类实现文本文件内容的读取。二、常用构造方法三、使用FileInputStream类按多字节读取数据1.示例 2、分析四、常见错误  今天的总结就到这里啦,拜拜!  ......
  • java 并发编程面试(1)
    一、单例模式的DCL为啥要加volatile?避免指令重排,获取到未初始化完成的对象。单例模式的懒汉模式确保线程安全的机制DCLpublicclassMyTest{privatestaticMyTestmyTest;publicstaticMyTestgetInstance(){if(myTest==null){//check......