​​​​​​​检查无向图是否包含循环

给定一个已连接的无向图,请查找它是否包含任何循环。

例如,以下图形包含一个循环2–5–10–6–2

循环广度第一棵树

推荐阅读:

 

1.使用BFS

当我们从无v向图中的任何顶点进行广度优先搜索(BFS)时,我们可能会遇到一个交叉边缘,该边缘指向先前发现的顶点,该顶点既不是当前顶点的祖先也不是其后代。每个“交叉边缘”在无向图中定义一个循环。如果交叉边缘x —> y,则因为y已经发现,我们从路径vy(或来自yv,因为是无向图),其中v是BFS的起始顶点。因此,可以说我们有一条v ~~ x ~ y ~~ v形成循环的路径。(此处,~~表示路径中的另一个边,并~表示直接边)。

以下是演示它的C ++,Java和Python程序:

 

  • C ++
  • 爪哇
  • Python

 

 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
import java.util.*;
 
// A class to store a graph edge
class Edge
{
    int source, dest;
 
    public Edge(int source, int dest)
    {
        this.source = source;
        this.dest = dest;
    }
}
 
// A class to represent a graph object
class Graph
{
    // A list of lists to represent an adjacency list
    List<List<Integer>> adjList = null;
 
    // Constructor
    Graph(List<Edge> edges, int N)
    {
        adjList = new ArrayList<>();
 
        for (int i = 0; i < N; i++) {
            adjList.add(new ArrayList<>());
        }
 
        // add edges to the undirected graph
        for (Edge edge: edges)
        {
            int src = edge.source;
            int dest = edge.dest;
 
            adjList.get(src).add(dest);
            adjList.get(dest).add(src);
        }
    }
}
 
// Node to store vertex and its parent info in BFS
class Node
{
    int v, parent;
 
    Node(int v, int parent)
    {
        this.v = v;
        this.parent = parent;
    }
}
 
class Main
{
    // Perform BFS on the graph starting from vertex `src` and
    // return true if a cycle is found in the graph
    public static boolean BFS(Graph graph, int src, int N)
    {
        // to keep track of whether a vertex is discovered or not
        boolean[] discovered = new boolean[N];
 
        // mark the source vertex as discovered
        discovered[src] = true;
 
        // create a queue for doing BFS and
        // enqueue source vertex
        Queue<Node> q = new ArrayDeque<>();
        q.add(new Node(src, -1));
 
        // loop till queue is empty
        while (!q.isEmpty())
        {
            // dequeue front node and print it
            Node node = q.poll();
 
            // do for every edge `v —> u`
            for (int u: graph.adjList.get(node.v))
            {
                if (!discovered[u])
                {
                    // mark it as discovered
                    discovered[u] = true;
 
                    // construct the queue node containing info
                    // about vertex and enqueue it
                    q.add(new Node(u, node.v));
                }
 
                // `u` is discovered, and `u` is not a parent
                else if (u != node.parent)
                {
                    // we found a cross-edge, i.e., the cycle is found
                    return true;
                }
            }
        }
 
        // no cross-edges were found in the graph
        return false;
    }
 
    public static void main(String[] args)
    {
        // List of graph edges as per the above diagram
        List<Edge> edges = Arrays.asList(
                                new Edge(1, 2), new Edge(1, 3), new Edge(1, 4),
                                new Edge(2, 5), new Edge(2, 6), new Edge(5, 9),
                                new Edge(5, 10), new Edge(4, 7), new Edge(4, 8),
                                new Edge(7, 11), new Edge(7, 12), new Edge(6, 10)
                                // edge `6 —> 10` introduces a cycle in the graph
                            );
 
        // total number of nodes in the graph
        final int N = 13;
 
        // build a graph from the given edges
        Graph graph = new Graph(edges, N);
 
        // Perform BFS traversal in connected components of a graph
        if (BFS(graph, 1, N)) {
            System.out.println("The graph contains a cycle");
        }
        else {
            System.out.println("The graph doesn't contain any cycle");
        }
    }
}

 

下载  运行代码

输出:

图形包含一个循环

 

 

2.使用DFS

下图包含一个周期8—9—11—12—8

循环深度第一棵树

 
当我们从无向图中的任何顶点进行深度优先搜索(DFS)时v,我们可能会遇到一个后缘,该后缘指向vDFS树中当前顶点的祖先之一。每个“后沿”在无向图中定义一个循环。如果后边缘是x —> y,则既然y是node的祖先x,我们有一条从y到的路径x。因此,可以说我们有一条y ~~ x ~ y形成循环的路径。(此处,~~表示路径中的另一个边,并~表示直接边)。

以下是基于上述思想的C ++,Java和Python实现:

 

  • C ++
  • 爪哇
  • Python

 

 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
import java.util.*;
 
// A class to store a graph edge
class Edge
{
    int source, dest;
 
    public Edge(int source, int dest)
    {
        this.source = source;
        this.dest = dest;
    }
}
 
// A class to represent a graph object
class Graph
{
    // A list of lists to represent an adjacency list
    List<List<Integer>> adjList = null;
 
    // Constructor
    Graph(List<Edge> edges, int N)
    {
        adjList = new ArrayList<>(N);
 
        for (int i = 0; i < N; i++) {
            adjList.add(i, new ArrayList<>());
        }
 
        // add edges to the undirected graph
        for (Edge edge: edges)
        {
            int src = edge.source;
            int dest = edge.dest;
 
            adjList.get(src).add(dest);
            adjList.get(dest).add(src);
        }
    }
}
 
class Main
{
    // Function to perform DFS traversal on the graph on a graph
    public static boolean DFS(Graph graph, int v,
                        boolean[] discovered, int parent)
    {
        // mark the current node as discovered
        discovered[v] = true;
 
        // do for every edge `v —> w`
        for (int w: graph.adjList.get(v))
        {
            // if `w` is not discovered
            if (!discovered[w])
            {
                if (DFS(graph, w, discovered, v)) {
                    return true;
                }
            }
 
            // if `w` is discovered, and `w` is not a parent
            else if (w != parent)
            {
                // we found a back-edge (cycle)
                return true;
            }
        }
 
        // No back-edges were found in the graph
        return false;
    }
 
    public static void main(String[] args)
    {
        // List of graph edges as per the above diagram
        List<Edge> edges = Arrays.asList(
                                new Edge(1, 2), new Edge(1, 7),
                                new Edge(1, 8), new Edge(2, 3),
                                new Edge(2, 6), new Edge(3, 4),
                                new Edge(3, 5), new Edge(8, 9),
                                new Edge(8, 12), new Edge(9, 10),
                                new Edge(9, 11), new Edge(11, 12)
                                // edge `11 —> 12` introduces a cycle in the graph
                            );
 
        // total number of nodes in the graph
        final int N = 13;
 
        // build a graph from the given edges
        Graph graph = new Graph(edges, N);
 
        // to keep track of whether a vertex is discovered or not
        boolean[] discovered = new boolean[N];
 
        // Perform DFS traversal from the first vertex
        if (DFS(graph, 1, discovered, -1)) {
            System.out.println("The graph contains a cycle");
        }
        else {
            System.out.println("The graph doesn't contain any cycle");
        }
    }
}

 

下载  运行代码

输出:

图形包含一个循环

 

 

上述解决方案的时间复杂度为O(V + E),其中V和和E分别是图形中顶点和边缘的总数。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值