File size: 7,904 Bytes
283ba4a | 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 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 | """Connected components."""
import networkx as nx
from networkx.utils.decorators import not_implemented_for
from ...utils import arbitrary_element
__all__ = [
"number_connected_components",
"connected_components",
"is_connected",
"node_connected_component",
]
@not_implemented_for("directed")
@nx._dispatchable
def connected_components(G):
"""Generate connected components.
The connected components of an undirected graph partition the graph into
disjoint sets of nodes. Each of these sets induces a subgraph of graph
`G` that is connected and not part of any larger connected subgraph.
A graph is connected (:func:`is_connected`) if, for every pair of distinct
nodes, there is a path between them. If there is a pair of nodes for
which such path does not exist, the graph is not connected (also referred
to as "disconnected").
A graph consisting of a single node and no edges is connected.
Connectivity is undefined for the null graph (graph with no nodes).
Parameters
----------
G : NetworkX graph
An undirected graph
Yields
------
comp : set
A set of nodes in one connected component of the graph.
Raises
------
NetworkXNotImplemented
If G is directed.
Examples
--------
Generate a sorted list of connected components, largest first.
>>> G = nx.path_graph(4)
>>> nx.add_path(G, [10, 11, 12])
>>> [len(c) for c in sorted(nx.connected_components(G), key=len, reverse=True)]
[4, 3]
If you only want the largest connected component, it's more
efficient to use max instead of sort.
>>> largest_cc = max(nx.connected_components(G), key=len)
To create the induced subgraph of each component use:
>>> S = [G.subgraph(c).copy() for c in nx.connected_components(G)]
See Also
--------
number_connected_components
is_connected
number_weakly_connected_components
number_strongly_connected_components
Notes
-----
This function is for undirected graphs only. For directed graphs, use
:func:`strongly_connected_components` or
:func:`weakly_connected_components`.
The algorithm is based on a Breadth-First Search (BFS) traversal and its
time complexity is $O(n + m)$, where $n$ is the number of nodes and $m$ the
number of edges in the graph.
"""
seen = set()
n = len(G) # must be outside the loop to avoid performance hit with graph views
for v in G:
if v not in seen:
c = _plain_bfs(G, n - len(seen), v)
seen.update(c)
yield c
@not_implemented_for("directed")
@nx._dispatchable
def number_connected_components(G):
"""Returns the number of connected components.
The connected components of an undirected graph partition the graph into
disjoint sets of nodes. Each of these sets induces a subgraph of graph
`G` that is connected and not part of any larger connected subgraph.
A graph is connected (:func:`is_connected`) if, for every pair of distinct
nodes, there is a path between them. If there is a pair of nodes for
which such path does not exist, the graph is not connected (also referred
to as "disconnected").
A graph consisting of a single node and no edges is connected.
Connectivity is undefined for the null graph (graph with no nodes).
Parameters
----------
G : NetworkX graph
An undirected graph.
Returns
-------
n : integer
Number of connected components
Raises
------
NetworkXNotImplemented
If G is directed.
Examples
--------
>>> G = nx.Graph([(0, 1), (1, 2), (5, 6), (3, 4)])
>>> nx.number_connected_components(G)
3
See Also
--------
connected_components
is_connected
number_weakly_connected_components
number_strongly_connected_components
Notes
-----
This function is for undirected graphs only. For directed graphs, use
:func:`number_strongly_connected_components` or
:func:`number_weakly_connected_components`.
The algorithm is based on a Breadth-First Search (BFS) traversal and its
time complexity is $O(n + m)$, where $n$ is the number of nodes and $m$ the
number of edges in the graph.
"""
return sum(1 for _ in connected_components(G))
@not_implemented_for("directed")
@nx._dispatchable
def is_connected(G):
"""Returns True if the graph is connected, False otherwise.
A graph is connected if, for every pair of distinct nodes, there is a
path between them. If there is a pair of nodes for which such path does
not exist, the graph is not connected (also referred to as "disconnected").
A graph consisting of a single node and no edges is connected.
Connectivity is undefined for the null graph (graph with no nodes).
Parameters
----------
G : NetworkX Graph
An undirected graph.
Returns
-------
connected : bool
True if the graph is connected, False otherwise.
Raises
------
NetworkXNotImplemented
If G is directed.
Examples
--------
>>> G = nx.path_graph(4)
>>> print(nx.is_connected(G))
True
See Also
--------
is_strongly_connected
is_weakly_connected
is_semiconnected
is_biconnected
connected_components
Notes
-----
This function is for undirected graphs only. For directed graphs, use
:func:`is_strongly_connected` or :func:`is_weakly_connected`.
The algorithm is based on a Breadth-First Search (BFS) traversal and its
time complexity is $O(n + m)$, where $n$ is the number of nodes and $m$ the
number of edges in the graph.
"""
n = len(G)
if n == 0:
raise nx.NetworkXPointlessConcept(
"Connectivity is undefined for the null graph."
)
return len(next(connected_components(G))) == n
@not_implemented_for("directed")
@nx._dispatchable
def node_connected_component(G, n):
"""Returns the set of nodes in the component of graph containing node n.
A connected component is a set of nodes that induces a subgraph of graph
`G` that is connected and not part of any larger connected subgraph.
A graph is connected (:func:`is_connected`) if, for every pair of distinct
nodes, there is a path between them. If there is a pair of nodes for
which such path does not exist, the graph is not connected (also referred
to as "disconnected").
A graph consisting of a single node and no edges is connected.
Connectivity is undefined for the null graph (graph with no nodes).
Parameters
----------
G : NetworkX Graph
An undirected graph.
n : node label
A node in G
Returns
-------
comp : set
A set of nodes in the component of G containing node n.
Raises
------
NetworkXNotImplemented
If G is directed.
Examples
--------
>>> G = nx.Graph([(0, 1), (1, 2), (5, 6), (3, 4)])
>>> nx.node_connected_component(G, 0) # nodes of component that contains node 0
{0, 1, 2}
See Also
--------
connected_components
Notes
-----
This function is for undirected graphs only.
The algorithm is based on a Breadth-First Search (BFS) traversal and its
time complexity is $O(n + m)$, where $n$ is the number of nodes and $m$ the
number of edges in the graph.
"""
return _plain_bfs(G, len(G), n)
def _plain_bfs(G, n, source):
"""A fast BFS node generator"""
adj = G._adj
seen = {source}
nextlevel = [source]
while nextlevel:
thislevel = nextlevel
nextlevel = []
for v in thislevel:
for w in adj[v]:
if w not in seen:
seen.add(w)
nextlevel.append(w)
if len(seen) == n:
return seen
return seen
|