C++ Reference

C++ Reference: Graph

connectivity.h
Go to the documentation of this file.
1 // Copyright 2010-2018 Google LLC
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 // http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13 
14 // Graph connectivity algorithm for undirected graphs.
15 // Memory consumption: O(n) where m is the number of arcs and n the number
16 // of nodes.
17 // TODO(user): add depth-first-search based connectivity for directed graphs.
18 // TODO(user): add depth-first-search based biconnectivity for directed graphs.
19 
20 #ifndef OR_TOOLS_GRAPH_CONNECTIVITY_H_
21 #define OR_TOOLS_GRAPH_CONNECTIVITY_H_
22 
23 #include <vector>
24 
25 #include "ortools/base/integral_types.h"
26 #include "ortools/base/logging.h"
27 #include "ortools/base/macros.h"
28 
29 namespace operations_research {
30 
31 // Template class implementing a Union-Find algorithm with path compression for
32 // maintaining the connected components of a graph.
33 // See Cormen et al. 2nd Edition. MIT Press, 2001. ISBN 0-262-03293-7.
34 // Chapter 21: Data structures for Disjoint Sets, pp. 498-524.
35 // and Tarjan (1975). Efficiency of a Good But Not Linear Set
36 // Union Algorithm. Journal of the ACM 22(2):215-225
37 // It is implemented as a template so that the size of NodeIndex can be chosen
38 // depending on the size of the graphs considered.
39 // The main interest is that arcs do not need to be kept. Thus the memory
40 // complexity is O(n) where n is the number of nodes in the graph.
41 // The complexity of this algorithm is O(n . alpha(n)) where alpha(n) is
42 // the inverse Ackermann function. alpha(n) <= log(log(log(..log(log(n))..)
43 // In practice alpha(n) <= 5.
44 // See Tarjan and van Leeuwen (1984). Worst-case analysis of set union
45 // algorithms. Journal of the ACM 31(2):245-281.
46 //
47 // Usage example:
48 // ConnectedComponents<int, int> components;
49 // components.Init(num_nodes);
50 // for (int arc = 0; arc < num_arcs; ++arc) {
51 // components.AddArc(tail[arc], head[arc]);
52 // }
53 // int num_connected_components = components.GetNumberOfConnectedComponents();
54 // if (num_connected_components == 1) {
55 // // Graph is completely connected.
56 // }
57 // // Group the nodes in the same connected component together.
58 // // group[class_number][i] contains the i-th node in group class_number.
59 // hash_map<int, vector<int> > group(num_connected_components);
60 // for (int node = 0; node < num_nodes; ++node) {
61 // group[components.GetClassRepresentative(node)].push_back(node);
62 // }
63 //
64 // Keywords: graph, connected components.
65 
66 template <typename NodeIndex, typename ArcIndex>
68  public:
69  ConnectedComponents() : num_nodes_(0), class_(), class_size_() {}
70 
71  // Reserves memory for num_nodes and resets the data structures.
72  void Init(NodeIndex num_nodes) {
73  CHECK_GE(num_nodes, 0);
74  num_nodes_ = num_nodes;
75  class_.resize(num_nodes_);
76  class_size_.assign(num_nodes_, 1);
77  for (NodeIndex node = 0; node < num_nodes_; ++node) {
78  class_[node] = node;
79  }
80  }
81 
82  // Adds the information that NodeIndex tail and NodeIndex head are connected.
83  void AddArc(NodeIndex tail, NodeIndex head) {
84  const NodeIndex tail_class = CompressPath(tail);
85  const NodeIndex head_class = CompressPath(head);
86  if (tail_class != head_class) {
87  MergeClasses(tail_class, head_class);
88  }
89  }
90 
91  // Adds a complete StarGraph to the object. Note that Depth-First Search
92  // is a better algorithm for finding connected components on graphs.
93  // TODO(user): implement Depth-First Search-based connected components finder.
94  template <typename Graph>
95  void AddGraph(const Graph& graph) {
96  Init(graph.num_nodes());
97  for (NodeIndex tail = 0; tail < graph.num_nodes(); ++tail) {
98  for (typename Graph::OutgoingArcIterator it(graph, tail); it.Ok();
99  it.Next()) {
100  AddArc(tail, graph.Head(it.Index()));
101  }
102  }
103  }
104 
105  // Compresses the path for node.
107  CheckNodeBounds(node);
108  NodeIndex parent = node;
109  while (parent != class_[parent]) {
110  CheckNodeBounds(class_[parent]);
111  CheckNodeBounds(class_[class_[parent]]);
112  parent = class_[parent];
113  }
114  while (node != class_[node]) {
115  const NodeIndex old_parent = class_[node];
116  class_[node] = parent;
117  node = old_parent;
118  }
119  return parent;
120  }
121 
122  // Returns the equivalence class representative for node.
124  return CompressPath(node);
125  }
126 
127  // Returns the number of connected components. Allocates num_nodes_ bits for
128  // the computation.
130  NodeIndex number = 0;
131  for (NodeIndex node = 0; node < num_nodes_; ++node) {
132  if (class_[node] == node) ++number;
133  }
134  return number;
135  }
136 
137  // Merges the equivalence classes of node1 and node2.
138  void MergeClasses(NodeIndex node1, NodeIndex node2) {
139  // It's faster (~10%) to swap the two values and have a single piece of
140  // code for merging the classes.
141  CheckNodeBounds(node1);
142  CheckNodeBounds(node2);
143  if (class_size_[node1] < class_size_[node2]) {
144  std::swap(node1, node2);
145  }
146  class_[node2] = node1;
147  class_size_[node1] += class_size_[node2];
148  }
149 
150  private:
151  void CheckNodeBounds(NodeIndex node_index) {
152  DCHECK_LE(0, node_index);
153  DCHECK_LT(node_index, num_nodes_);
154  }
155  // The exact number of nodes in the graph.
156  NodeIndex num_nodes_;
157 
158  // The equivalence class representative for each node.
159  std::vector<NodeIndex> class_;
160 
161  // The size of each equivalence class of each node. Used to compress the paths
162  // and therefore achieve better time complexity.
163  std::vector<NodeIndex> class_size_;
164 
165  DISALLOW_COPY_AND_ASSIGN(ConnectedComponents);
166 };
167 
168 } // namespace operations_research
169 
170 #endif // OR_TOOLS_GRAPH_CONNECTIVITY_H_
ConnectedComponents()
Definition: connectivity.h:69
ListGraph Graph
Definition: graph.h:2354
Definition: christofides.h:33
NodeIndex GetClassRepresentative(NodeIndex node)
Definition: connectivity.h:123
NodeIndex CompressPath(NodeIndex node)
Definition: connectivity.h:106
void Init(NodeIndex num_nodes)
Definition: connectivity.h:72
NodeIndex GetNumberOfConnectedComponents()
Definition: connectivity.h:129
void MergeClasses(NodeIndex node1, NodeIndex node2)
Definition: connectivity.h:138
void AddGraph(const Graph &graph)
Definition: connectivity.h:95
int32 NodeIndex
Definition: ebert_graph.h:192
void AddArc(NodeIndex tail, NodeIndex head)
Definition: connectivity.h:83
Definition: connectivity.h:67