在一个无向图中找环_无向图找环算法-程序员宅基地

技术标签: dfs  Graph Algorithm  

目录索引:畅游面试中算法题集锦

在一个无向图中找环

PART1:DFS

请添加图片描述

Approach:

从每个未访问的节点运行 DFS。深度优先遍历可用于检测图中的循环。连通图的 DFS 生成一棵树。仅当图中存在回边Back Edge:从一个顶点指向其祖先顶点的边时,图中才存在环。回边Back Edge是将节点连接到自身(自循环)或其在 DFS 生成的树中的祖先之一的边。
要找到其任何祖先的回边Back Edge,保留一个访问过的数组,如果任何访问过的节点都有回边Back Edge,则存在一个循环并返回 true。

Algorithm:
  1. 使用给定数量的边和顶点创建图。
  2. 创建一个具有当前索引或顶点、访问过的数组和父节点的递归函数。
  3. 将当前节点标记为visited。
  4. 找出所有没有访问过且与当前节点相邻的顶点。递归调用这些顶点的函数,如果递归函数返回true返回true。
  5. 如果相邻节点不是父节点并且已经访问过,则返回 true。
  6. 创建一个包装类,为所有顶点调用递归函数,如果任何函数返回 true,则返回 true。
  7. 否则,如果对于所有顶点,函数返回 false 返回 false。

请添加图片描述

下图说明的是code中的g1图,无向图找环的过程

请添加图片描述

Code:
static class Graph {
    
    private int V;
    private LinkedList<Integer>[] adj;

    public Graph(int V) {
    
        this.V = V;
        adj = new LinkedList[V];
        for (int i = 0; i < V; i++) {
    
            adj[i] = new LinkedList<>();
        }
    }

    private void addEdge(int u, int v) {
    
        adj[u].add(v);
        adj[v].add(u);
    }

    /**
     * 从u出发,visited[] 标记节点是否访问过,parent表示父亲节点
     * 是否存在一个环
     */
    public boolean isCyclicUtil(int u, boolean[] visited, int parent) {
    
        visited[u] = true;//标记当前节点被访问过
        for (int v : adj[u]) {
    //遍历u的相邻节点
            if (!visited[v]) {
    //第一次访问v
                if (isCyclicUtil(v, visited, u)) return true;
            } else if (v != parent) return true;//相邻节点不是父节点且被访问过
        }
        return false;
    }

    public boolean isCyclic() {
    
        boolean[] visited = new boolean[V];
        for (int u = 0; u < V; u++) {
    
            if (!visited[u]) {
    
                if (isCyclicUtil(u, visited, -1)) return true;
            }
        }
        return false;
    }

    public static void main(String args[]) {
    
        Graph g1 = new Graph(5);
        g1.addEdge(1, 0);
        g1.addEdge(0, 2);
        g1.addEdge(2, 1);
        g1.addEdge(0, 3);
        g1.addEdge(3, 4);
        if (g1.isCyclic())
            System.out.println("Graph  contains cycle");
        else
            System.out.println("Graph  doesn 't contains cycle");
        Graph g2 = new Graph(3);
        g2.addEdge(0, 1);
        g2.addEdge(1, 2);
        if (g2.isCyclic())
            System.out.println("Graph  contains cycle");
        else
            System.out.println("Graph doesn 't contains cycle");
    }
    //Graph  contains cycle
	//Graph doesn 't contains cycle

PART2:Disjoint Set

带路径压缩的参考后文:一文掌握并查集算法

static class Graph {
    


    int V, E;//顶点和边的数量
    Edge[] edges;

    class Edge {
    
        int src;
        int dest;


    }

    //初始化
    public Graph(int v, int e) {
    
        V = v;
        E = e;
        edges = new Edge[E];
        for (int i = 0; i < E; i++) {
    
            edges[i] = new Edge();
        }
    }

    //返回i这个节点的子集
    private int find(int[] parents, int i) {
    
        if (parents[i] == -1) return i;
        return find(parents, parents[i]);
    }

    //合并两个子集,没有带路径压缩
    private void union(int[] parents, int x, int y) {
    
        parents[x] = y;
    }

    public int isCycle(Graph graph) {
    
        int[] parents = new int[graph.V];//分配V个节点的parents数组
        Arrays.fill(parents, -1);//初始化
        for (int i = 0; i < graph.E; i++) {
    
            Edge edge = graph.edges[i];
            int x = graph.find(parents, edge.src);
            int y = graph.find(parents, edge.dest);
            if (x == y) return 1;
            graph.union(parents, x, y);
        }
        return 0;
    }

    // Driver Method
    public static void main(String[] args) {
    
/* Let us create the following graph
0
| \
|  \
1---2 */
        int V = 3, E = 3;
        Graph graph = new Graph(V, E);
        // add edge 0-1
        graph.edges[0].src = 0;
        graph.edges[0].dest = 1;
        // add edge 1-2
        graph.edges[1].src = 1;
        graph.edges[1].dest = 2;
        // add edge 0-2
        graph.edges[2].src = 0;
        graph.edges[2].dest = 2;
        if (graph.isCycle(graph) == 1)
            System.out.println("graph contains cycle");
        else
            System.out.println("graph doesn't contain cycle");
    }

}

Reference

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/wat1r/article/details/119443596

智能推荐

GitHub Copilot Workspace:欢迎进入原生Copilot开发环境

一旦你对计划感到满意,你可以直接在Copilot Workspace中运行你的代码,跳入底层的GitHub Codespace,并调整所有代码更改直到你对最终结果感到满意。在去年GitHub Universe的早期展示后,今天,我们正重新想象开发者体验的本质,推出了GitHub Copilot Workspace的技术预览版:一个原生支持Copilot的开发环境。然后剩下的就是提交你的拉取请求,运行你的GitHub Actions,进行安全代码扫描,并请求你的团队成员进行人工代码审查。而且完全可以编辑……

【微机原理复试面试简答题汇总】_微机原理复试常见问题-程序员宅基地

文章浏览阅读1.2k次,点赞6次,收藏29次。提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档。_微机原理复试常见问题

vue快速入门(五十五)插槽基本用法

注释很详细,直接上代码……

Hbase 的架构详解_hbase架构-程序员宅基地

文章浏览阅读5.6k次,点赞10次,收藏19次。Hbase 作为 NoSQL 数据库的代表,属于三驾马车之一 BigTable 的对应实现,HBase 的出现很好地弥补了大数据快速查询能力的空缺。在前面咱们也有介绍过 HBase 的数据模型,感兴趣的小伙伴可以翻看下。谈谈你对HBase数据模型的认识?HBase 的核心架构由五部分组成,分别是 HBase Client、HMaster、Region Server、ZooKeeper 以及 HDFS。它的架构组成如下图所示。下面我们对 HBase 架构组成的每一部分详细介绍一下。1.HBas_hbase架构

Windows下Java环境配置教程_windows java环境配置-程序员宅基地

文章浏览阅读3.7w次,点赞171次,收藏430次。这篇博客介绍Java环境的配置,主要是安装JDK,以及path、JAVA_hOME、CLASSPAT的配置,还会介绍配置这些的原因。_windows java环境配置

【SeedLab】BGP Exploration and Attack Lab_bgp seed-程序员宅基地

文章浏览阅读2.3k次。本实验需要使用SEED互联网仿真器(已集成到docker配置文件)。启动docker容器,配置文件在/Labsetup/outputs/目录下。由于要配置很多docker容器,所以构建+启动过程会比较漫长。.随着docker启动,仿真器也随之运行,仿真器所用到的设备均为docker容器。..._bgp seed

随便推点

23种设计模式(第三章结构型模式7种)_设计模式符合-程序员宅基地

文章浏览阅读307次。结构型模式结构型模式描述如何将类或对象按某种布局组成更大的结构。它分为类结构型模式和对象结构型模式,前者采用继承机制来组织接口和类,后者釆用组合或聚合来组合对象。由于组合关系或聚合关系比继承关系耦合度低,满足“合成复用原则”,所以对象结构型模式比类结构型模式具有更大的灵活性。结构型模式分为以下 7 种:代理模式适配器模式装饰者模式桥接模式外观模式组合模式享元模式5.1 代理模式5.1.1 概述由于某些原因需要给某对象提供一个代理以控制对该对象的访问。这时,访问对象不适合或者不能_设计模式符合

链表中为何使用二级指针_链表初始化为什么要二级指针-程序员宅基地

文章浏览阅读3.6k次,点赞30次,收藏128次。本篇目录前言参数的调用方式传值调用传址调用传引用调用示例说明使用二级指针/一级指针创建链表时的对比主函数中作此调用使用二级指针创建链表使用一级指针创建链表会成功吗销毁链表时二级指针和一级指针的对比使用二级指针销毁链表使用一级指针销毁链表会成功吗总结完整代码参考来源前言在学习数据结构时,在链表初始化或者销毁链表的时候,经常使用二级指针或者一级指针的引用,这是为什么呢?同样是指向内存单元的地址,为什么就不能使用一级指针呢?使用一级指针去初始化或者是销毁链表的时候,究竟会发生什么呢?到底什么时候该用二级指针,_链表初始化为什么要二级指针

win10通过pycharm远程登录到Linux服务器,并通过matplotlib作图_pycharm连接服务绘图-程序员宅基地

文章浏览阅读3.6k次,点赞9次,收藏24次。准备工作:1.下载专业版本的Pycharm。这里为大家提供18版本的链接: https://pan.baidu.com/s/1-GYSJvUx9JoUujPfu3EPwA密码: p283 或者直接去官网下载: https://www.jetbrains.com/pycharm/download/download-thanks.html?platform=windows2.安装并..._pycharm连接服务绘图

更改 MATLAB 当前文件夹 或 将其文件夹添加到 MATLAB 路径。出错_manually add this path to the matlab path-程序员宅基地

文章浏览阅读8.7k次。更改 MATLAB 当前文件夹 或 将其文件夹添加到 MATLAB 路径。出错_manually add this path to the matlab path

iOS之UIView动画_oc uiview animate 关键帧-程序员宅基地

文章浏览阅读5.5k次。在AppStore中的应用越来越重视动画效果的使用,一个良好动画效果可以让两个状态之间平滑地过度,也可以利用动画吸引住用户的眼球_oc uiview animate 关键帧

代码报错原因和处理方法-程序员宅基地

文章浏览阅读8.7k次。代码错误的原因和调试方法_代码报错