connected.py 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. """Connected components."""
  2. import networkx as nx
  3. from networkx.utils.decorators import not_implemented_for
  4. from ...utils import arbitrary_element
  5. __all__ = [
  6. "number_connected_components",
  7. "connected_components",
  8. "is_connected",
  9. "node_connected_component",
  10. ]
  11. @nx._dispatch
  12. @not_implemented_for("directed")
  13. def connected_components(G):
  14. """Generate connected components.
  15. Parameters
  16. ----------
  17. G : NetworkX graph
  18. An undirected graph
  19. Returns
  20. -------
  21. comp : generator of sets
  22. A generator of sets of nodes, one for each component of G.
  23. Raises
  24. ------
  25. NetworkXNotImplemented
  26. If G is directed.
  27. Examples
  28. --------
  29. Generate a sorted list of connected components, largest first.
  30. >>> G = nx.path_graph(4)
  31. >>> nx.add_path(G, [10, 11, 12])
  32. >>> [len(c) for c in sorted(nx.connected_components(G), key=len, reverse=True)]
  33. [4, 3]
  34. If you only want the largest connected component, it's more
  35. efficient to use max instead of sort.
  36. >>> largest_cc = max(nx.connected_components(G), key=len)
  37. To create the induced subgraph of each component use:
  38. >>> S = [G.subgraph(c).copy() for c in nx.connected_components(G)]
  39. See Also
  40. --------
  41. strongly_connected_components
  42. weakly_connected_components
  43. Notes
  44. -----
  45. For undirected graphs only.
  46. """
  47. seen = set()
  48. for v in G:
  49. if v not in seen:
  50. c = _plain_bfs(G, v)
  51. seen.update(c)
  52. yield c
  53. def number_connected_components(G):
  54. """Returns the number of connected components.
  55. Parameters
  56. ----------
  57. G : NetworkX graph
  58. An undirected graph.
  59. Returns
  60. -------
  61. n : integer
  62. Number of connected components
  63. Examples
  64. --------
  65. >>> G = nx.Graph([(0, 1), (1, 2), (5, 6), (3, 4)])
  66. >>> nx.number_connected_components(G)
  67. 3
  68. See Also
  69. --------
  70. connected_components
  71. number_weakly_connected_components
  72. number_strongly_connected_components
  73. Notes
  74. -----
  75. For undirected graphs only.
  76. """
  77. return sum(1 for cc in connected_components(G))
  78. @nx._dispatch
  79. @not_implemented_for("directed")
  80. def is_connected(G):
  81. """Returns True if the graph is connected, False otherwise.
  82. Parameters
  83. ----------
  84. G : NetworkX Graph
  85. An undirected graph.
  86. Returns
  87. -------
  88. connected : bool
  89. True if the graph is connected, false otherwise.
  90. Raises
  91. ------
  92. NetworkXNotImplemented
  93. If G is directed.
  94. Examples
  95. --------
  96. >>> G = nx.path_graph(4)
  97. >>> print(nx.is_connected(G))
  98. True
  99. See Also
  100. --------
  101. is_strongly_connected
  102. is_weakly_connected
  103. is_semiconnected
  104. is_biconnected
  105. connected_components
  106. Notes
  107. -----
  108. For undirected graphs only.
  109. """
  110. if len(G) == 0:
  111. raise nx.NetworkXPointlessConcept(
  112. "Connectivity is undefined ", "for the null graph."
  113. )
  114. return sum(1 for node in _plain_bfs(G, arbitrary_element(G))) == len(G)
  115. @nx._dispatch
  116. @not_implemented_for("directed")
  117. def node_connected_component(G, n):
  118. """Returns the set of nodes in the component of graph containing node n.
  119. Parameters
  120. ----------
  121. G : NetworkX Graph
  122. An undirected graph.
  123. n : node label
  124. A node in G
  125. Returns
  126. -------
  127. comp : set
  128. A set of nodes in the component of G containing node n.
  129. Raises
  130. ------
  131. NetworkXNotImplemented
  132. If G is directed.
  133. Examples
  134. --------
  135. >>> G = nx.Graph([(0, 1), (1, 2), (5, 6), (3, 4)])
  136. >>> nx.node_connected_component(G, 0) # nodes of component that contains node 0
  137. {0, 1, 2}
  138. See Also
  139. --------
  140. connected_components
  141. Notes
  142. -----
  143. For undirected graphs only.
  144. """
  145. return _plain_bfs(G, n)
  146. def _plain_bfs(G, source):
  147. """A fast BFS node generator"""
  148. G_adj = G.adj
  149. seen = set()
  150. nextlevel = {source}
  151. while nextlevel:
  152. thislevel = nextlevel
  153. nextlevel = set()
  154. for v in thislevel:
  155. if v not in seen:
  156. seen.add(v)
  157. nextlevel.update(G_adj[v])
  158. return seen