|
1 // |
|
2 //======================================================================= |
|
3 // Copyright 1997-2001 University of Notre Dame. |
|
4 // Authors: Andrew Lumsdaine, Lie-Quan Lee, Jeremy G. Siek |
|
5 // |
|
6 // Distributed under the Boost Software License, Version 1.0. (See |
|
7 // accompanying file LICENSE_1_0.txt or copy at |
|
8 // http://www.boost.org/LICENSE_1_0.txt) |
|
9 //======================================================================= |
|
10 // |
|
11 |
|
12 #ifndef BOOST_INCREMENTAL_COMPONENTS_HPP |
|
13 #define BOOST_INCREMENTAL_COMPONENTS_HPP |
|
14 |
|
15 #include <boost/detail/iterator.hpp> |
|
16 #include <boost/graph/detail/incremental_components.hpp> |
|
17 |
|
18 namespace boost { |
|
19 |
|
20 // A connected component algorithm for the case when dynamically |
|
21 // adding (but not removing) edges is common. The |
|
22 // incremental_components() function is a preparing operation. Call |
|
23 // same_component to check whether two vertices are in the same |
|
24 // component, or use disjoint_set::find_set to determine the |
|
25 // representative for a vertex. |
|
26 |
|
27 // This version of connected components does not require a full |
|
28 // Graph. Instead, it just needs an edge list, where the vertices of |
|
29 // each edge need to be of integer type. The edges are assumed to |
|
30 // be undirected. The other difference is that the result is stored in |
|
31 // a container, instead of just a decorator. The container should be |
|
32 // empty before the algorithm is called. It will grow during the |
|
33 // course of the algorithm. The container must be a model of |
|
34 // BackInsertionSequence and RandomAccessContainer |
|
35 // (std::vector is a good choice). After running the algorithm the |
|
36 // index container will map each vertex to the representative |
|
37 // vertex of the component to which it belongs. |
|
38 // |
|
39 // Adapted from an implementation by Alex Stepanov. The disjoint |
|
40 // sets data structure is from Tarjan's "Data Structures and Network |
|
41 // Algorithms", and the application to connected components is |
|
42 // similar to the algorithm described in Ch. 22 of "Intro to |
|
43 // Algorithms" by Cormen, et. all. |
|
44 // |
|
45 // RankContainer is a random accessable container (operator[] is |
|
46 // defined) with a value type that can represent an integer part of |
|
47 // a binary log of the value type of the corresponding |
|
48 // ParentContainer (char is always enough) its size_type is no less |
|
49 // than the size_type of the corresponding ParentContainer |
|
50 |
|
51 // An implementation of disjoint sets can be found in |
|
52 // boost/pending/disjoint_sets.hpp |
|
53 |
|
54 template <class EdgeListGraph, class DisjointSets> |
|
55 void incremental_components(EdgeListGraph& g, DisjointSets& ds) |
|
56 { |
|
57 typename graph_traits<EdgeListGraph>::edge_iterator e, end; |
|
58 for (tie(e,end) = edges(g); e != end; ++e) |
|
59 ds.union_set(source(*e,g),target(*e,g)); |
|
60 } |
|
61 |
|
62 template <class ParentIterator> |
|
63 void compress_components(ParentIterator first, ParentIterator last) |
|
64 { |
|
65 for (ParentIterator current = first; current != last; ++current) |
|
66 detail::find_representative_with_full_compression(first, current-first); |
|
67 } |
|
68 |
|
69 template <class ParentIterator> |
|
70 typename boost::detail::iterator_traits<ParentIterator>::difference_type |
|
71 component_count(ParentIterator first, ParentIterator last) |
|
72 { |
|
73 std::ptrdiff_t count = 0; |
|
74 for (ParentIterator current = first; current != last; ++current) |
|
75 if (*current == current - first) ++count; |
|
76 return count; |
|
77 } |
|
78 |
|
79 // This algorithm can be applied to the result container of the |
|
80 // connected_components algorithm to normalize |
|
81 // the components. |
|
82 template <class ParentIterator> |
|
83 void normalize_components(ParentIterator first, ParentIterator last) |
|
84 { |
|
85 for (ParentIterator current = first; current != last; ++current) |
|
86 detail::normalize_node(first, current - first); |
|
87 } |
|
88 |
|
89 template <class VertexListGraph, class DisjointSets> |
|
90 void initialize_incremental_components(VertexListGraph& G, DisjointSets& ds) |
|
91 { |
|
92 typename graph_traits<VertexListGraph> |
|
93 ::vertex_iterator v, vend; |
|
94 for (tie(v, vend) = vertices(G); v != vend; ++v) |
|
95 ds.make_set(*v); |
|
96 } |
|
97 |
|
98 template <class Vertex, class DisjointSet> |
|
99 inline bool same_component(Vertex u, Vertex v, DisjointSet& ds) |
|
100 { |
|
101 return ds.find_set(u) == ds.find_set(v); |
|
102 } |
|
103 |
|
104 // considering changing the so that it initializes with a pair of |
|
105 // vertex iterators and a parent PA. |
|
106 |
|
107 template <class IndexT> |
|
108 class component_index |
|
109 { |
|
110 public://protected: (avoid friends for now) |
|
111 typedef std::vector<IndexT> MyIndexContainer; |
|
112 MyIndexContainer header; |
|
113 MyIndexContainer index; |
|
114 typedef typename MyIndexContainer::size_type SizeT; |
|
115 typedef typename MyIndexContainer::const_iterator IndexIter; |
|
116 public: |
|
117 typedef detail::component_iterator<IndexIter, IndexT, SizeT> |
|
118 component_iterator; |
|
119 class component { |
|
120 friend class component_index; |
|
121 protected: |
|
122 IndexT number; |
|
123 const component_index<IndexT>* comp_ind_ptr; |
|
124 component(IndexT i, const component_index<IndexT>* p) |
|
125 : number(i), comp_ind_ptr(p) {} |
|
126 public: |
|
127 typedef component_iterator iterator; |
|
128 typedef component_iterator const_iterator; |
|
129 typedef IndexT value_type; |
|
130 iterator begin() const { |
|
131 return iterator( comp_ind_ptr->index.begin(), |
|
132 (comp_ind_ptr->header)[number] ); |
|
133 } |
|
134 iterator end() const { |
|
135 return iterator( comp_ind_ptr->index.begin(), |
|
136 comp_ind_ptr->index.size() ); |
|
137 } |
|
138 }; |
|
139 typedef SizeT size_type; |
|
140 typedef component value_type; |
|
141 |
|
142 #if defined(BOOST_NO_TEMPLATED_ITERATOR_CONSTRUCTORS) |
|
143 template <class Iterator> |
|
144 component_index(Iterator first, Iterator last) |
|
145 : index(std::distance(first, last)) |
|
146 { |
|
147 std::copy(first, last, index.begin()); |
|
148 detail::construct_component_index(index, header); |
|
149 } |
|
150 #else |
|
151 template <class Iterator> |
|
152 component_index(Iterator first, Iterator last) |
|
153 : index(first, last) |
|
154 { |
|
155 detail::construct_component_index(index, header); |
|
156 } |
|
157 #endif |
|
158 |
|
159 component operator[](IndexT i) const { |
|
160 return component(i, this); |
|
161 } |
|
162 SizeT size() const { |
|
163 return header.size(); |
|
164 } |
|
165 |
|
166 }; |
|
167 |
|
168 } // namespace boost |
|
169 |
|
170 #endif // BOOST_INCREMENTAL_COMPONENTS_HPP |