判断无向图/有向图中是否存在环

  本文主要针对如何判断有向图/无向图中是否存在环的问题进行简单的论述。

一 无向图

1.利用DFS进行判断

利用DFS判断有向图是否存在环,是最为常用的一种方法,虽然这种方法很常用,但可参考的代码的实现比较少,下面对这种方法及其实现进行详细的阐述。

首先,利用DFS判断无向图中是否换的原理是:若在深度优先搜索的过程中遇到回边(即指向已经访问过的顶点的边),则必定存在环。

所以说,是否存在环的关键在于是否存在满足条件的“回边”,那么如何判断回边呢?

(1)首先,对图中的所有顶点定义三种状态:顶点未被访问过顶点刚开始被访问顶点被访问过并且其所有邻接点也被访问过。这三种状态,在visited数组中分别用0、1、2来表示。那么,存在环的情况可以定义为:在遍历过程中,发现某个顶点的一条边指向状态1的顶点,此时就存在环。

(2)此外,我们要定义一个father数组,用以存储在DFS过程中顶点的父顶点(或者说是生成树上的父节点)。其主要作用是为了区分邻接点中环中的顶点和遍历过程中的父节点 (单纯的用visited数组无法区分)。

整个过程的实现代码如下:

#define MAX_NUM 100
#define INF 0x7fffffff
/*DFS判断无向图中是否有环*/
class Graph
{
    public:
    int vertexNum;//顶点个数
    int arcNum;//弧的个数
    int vertex[MAX_NUM];//顶点表
    int arc[MAX_NUM][MAX_NUM];//弧信息表
};
int visited[MAX_NUM];//顶点访问表
int father[MAX_NUM];//父节点表问表
void DFS(int v,Graph G)
{
    visited[v] = 1;
    for(int i = 0 ; i < G.vertexNum; i++)
    {
        if(i != v && G.arc[v][i] != INF)//邻接矩阵中节点v的邻接点
        {
            if(visited[i] == 1 && father[i] != v)//不是父节点,而且还访问过,说明存在环
            {
                cout<<"图存在环";
                int temp = v;
                while(temp != i)
                {
                    cout<<temp<<"->";//输出环
                    temp = father[temp];
                }
                cout<<temp<<endl;
            }
            else
                if(visited[i] == 0)
                {
                    father[i] = v;//更新father数组
                    DFS(i,G);
                }

        }
    }
    visited[v] = 2;//遍历完所有的邻接点才变为状态2
}
void DFSTraverse(Graph G)
{
    memset(visited,0,sizeof(visited));
    memset(father,-1,sizeof(father));
    for(int i = 0 ; i < G.vertexNum; i++)
        if(!visited[i])
            DFS(i,G);
}

  

由此可见,visited数组相对于一般的情况,增加了个状态2,主要是为了防止在回溯过程中进行误判。所以才能仅用father数组和状态1判断存在环。

由于使用的是邻接矩阵来存储,所以该算法的时间复杂度为O(n^2),空间复杂度为O(n)。

2.其他方法本文不再详述。

二 有向图

1.拓扑排序

关于拓扑排序,资料很多,本文不再详述。

原文地址:https://www.cnblogs.com/wangkundentisy/p/9320499.html

时间: 2024-10-09 02:06:54

判断无向图/有向图中是否存在环的相关文章

拓扑排序,判断有向图中是否有环

[原创] 今天我们来聊聊有向图中环的判断,在数据结构中我们知道,通过拓扑排序可以判断有向图中是否存在环,对于有向图的存储我们采用邻接表的形势,这里为了简化链表的操作,我们省略了链表,避免了指针的麻烦,直接采用了c++中的vector来模拟链表,操作更加的方便:具体详细的使用,建议百度一下,这里不多说,至于拓扑排序的具体思想,相信大家应该都了解,那么直接上代码,如果有不理解的,建议查阅数据结构书籍,搞懂思想,结合这份代码,很好理解 1 #include <stdio.h> 2 #include

LeetCode 210. Course Schedule II(拓扑排序-求有向图中是否存在环)

和LeetCode 207. Course Schedule(拓扑排序-求有向图中是否存在环)类似. 注意到,在for (auto p: prerequistites)中特判了输入中可能出现的平行边或自环. 代码: class Solution { public: vector<int> findOrder(int numCourses, vector<pair<int, int>>& prerequisites) { // [0, {1, 2, 3}], me

数据结构和算法设计专题之---判断单链表中是否有环,环的长度,环的入口节点

题目: 给定一个单链表,只给出头指针head: 1.如何判断是否存在环? 2.如何知道环的长度? 3.如何找出环的连接点在哪里? 4.带环链表的长度是多少? 解法: 1.对于问题1,使用追赶的方法,设定两个指针slow.fast,从头指针开始,每次分别前进1步.2步.如存在环,则两者相遇:如不存在环,fast遇到NULL退出. 2.对于问题2,记录下问题1的碰撞点p,slow.fast从该点开始,再次碰撞所走过的操作数就是环的长度s. 3.问题3:有定理:碰撞点p到连接点的距离=头指针到连接点的

LeetCode 207. Course Schedule(拓扑排序-求有向图中是否存在环)

求有向图中是否有环. 法一:拓扑排序 用一个队列维护所有入度为0的节点,每次弹出一个节点v,查看从v可达的所有节点u; 将u的入读减一,若u的入度此时为0, 则将u加入队列. 在队列为空时,检查所有节点的入度,若所有节点入度都为0, 则存在这样的一个拓扑排序 -- 有向图中不存在环. 代码: class Solution { public: bool canFinish(int numCourses, vector<pair<int, int>>& prerequisite

判断有向图中是否有环

1 #include<iostream> 2 #include<malloc.h> 3 using namespace std; 4 #define maxNum 110 ///定义邻接举证的最大定点数 5 int pre[maxNum]; 6 int post[maxNum]; 7 int point=0;///pre和post的值 8 bool is_DAG=true;///标识位,表示有向无环图 9 /* 10 顶点颜色表 vis[u] 11 0 白色,未被访问过的节点标白色

判断有向图中是否存在环

1 // 将先修关系构成一张图,由每个数对的第二个数字向第一个数字连边. 2 // 首先将所有入度为0的点进队,准备拓扑排序. 3 // 宽搜过程中,将当前结点所关联的结点的入度减1:若发现新的入度为0的结点,则将其进队. 4 // 最后如果遍历了所有结点,则说明可以满足要求:否则,先修关系存在环. 5 6 //查找是否有环 7 class Solution 8 { 9 public: 10 bool canFinish(int numCourses, vector<vector<int>

判断单向链表中是否有环和查找环的入口

快慢指针 算法描述 定义两个指针slow, fast.slow指针一次走1个结点,fast指针一次走2个结点.如果链表中有环,那么慢指针一定会再某一个时刻追上快指针(slow == fast).如果没有环,则快指针会第一个走到NULL. 实现 结点定义如下: class Node { public Node next; public Object data; public static int sequence = 0; } 算法: /** * 快慢指针 * @param head * @ret

判断单链表中是否有环(循环链表)

有环的定义:链表的尾结点指向了链表中的某个结点,如下图所示 判断是否有环,两种方法: 方法1:使用p.q两个指针,p总是向前走,但q每次都从头开始走,对于每个节点看p走的步数和q是否一样,如上图所示:当p从6走到3时,共走了6步,此时若q从出发,则q只需要走两步就到达3的位置,因而步数不相等,出现矛盾,存在环. 方法2:快慢指针,定义p.q两个指针,p指针每次向前走一步,q每次向前走两步,若在某个时刻出现 p == q,则存在环. 具体代码实现: 1 #include<stdio.h> 2 #

查找有向图中所有的环

在对每个结点进行DFS的基础上进行了一些优化. 优化原理:若findCycle(0,e), 找到一个0-2-3的环,那么不再对2.3进行findCycle()函数.因为2或3若是构成有其它的环,findCycle(0)回溯到2或3时,会找出这些环. 1 import java.util.*; 2 3 public class GetAllCyclesForDirectedGraph{ 4 static List<Integer> trace; 5 static Set<Integer&g