gravatar
kpeter (Peter Kovacs)
kpeter@inf.elte.hu
Bug fix in the Euler iterators (#264) Handle the case when the first node is isolated.
0 1 0
default
1 file changed with 28 insertions and 16 deletions:
↑ Collapse diff ↑
Ignore white space 192 line context
1 1
/* -*- mode: C++; indent-tabs-mode: nil; -*-
2 2
 *
3 3
 * This file is a part of LEMON, a generic C++ optimization library.
4 4
 *
5 5
 * Copyright (C) 2003-2009
6 6
 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
7 7
 * (Egervary Research Group on Combinatorial Optimization, EGRES).
8 8
 *
9 9
 * Permission to use, modify and distribute this software is granted
10 10
 * provided that this copyright notice appears in all copies. For
11 11
 * precise terms see the accompanying LICENSE file.
12 12
 *
13 13
 * This software is provided "AS IS" with no warranty of any kind,
14 14
 * express or implied, and with no claim as to its suitability for any
15 15
 * purpose.
16 16
 *
17 17
 */
18 18

	
19 19
#ifndef LEMON_EULER_H
20 20
#define LEMON_EULER_H
21 21

	
22 22
#include<lemon/core.h>
23 23
#include<lemon/adaptors.h>
24 24
#include<lemon/connectivity.h>
25 25
#include <list>
26 26

	
27 27
/// \ingroup graph_properties
28 28
/// \file
29 29
/// \brief Euler tour
30 30
///
31 31
///This file provides an Euler tour iterator and ways to check
32 32
///if a digraph is euler.
33 33

	
34 34

	
35 35
namespace lemon {
36 36

	
37 37
  ///Euler iterator for digraphs.
38 38

	
39 39
  /// \ingroup graph_properties
40 40
  ///This iterator converts to the \c Arc type of the digraph and using
41 41
  ///operator ++, it provides an Euler tour of a \e directed
42 42
  ///graph (if there exists).
43 43
  ///
44 44
  ///For example
45 45
  ///if the given digraph is Euler (i.e it has only one nontrivial component
46 46
  ///and the in-degree is equal to the out-degree for all nodes),
47 47
  ///the following code will put the arcs of \c g
48 48
  ///to the vector \c et according to an
49 49
  ///Euler tour of \c g.
50 50
  ///\code
51 51
  ///  std::vector<ListDigraph::Arc> et;
52 52
  ///  for(DiEulerIt<ListDigraph> e(g),e!=INVALID;++e)
53 53
  ///    et.push_back(e);
54 54
  ///\endcode
55 55
  ///If \c g is not Euler then the resulted tour will not be full or closed.
56 56
  ///\sa EulerIt
57 57
  template<typename GR>
58 58
  class DiEulerIt
59 59
  {
60 60
    typedef typename GR::Node Node;
61 61
    typedef typename GR::NodeIt NodeIt;
62 62
    typedef typename GR::Arc Arc;
63 63
    typedef typename GR::ArcIt ArcIt;
64 64
    typedef typename GR::OutArcIt OutArcIt;
65 65
    typedef typename GR::InArcIt InArcIt;
66 66

	
67 67
    const GR &g;
68 68
    typename GR::template NodeMap<OutArcIt> nedge;
69 69
    std::list<Arc> euler;
70 70

	
71 71
  public:
72 72

	
73 73
    ///Constructor
74 74

	
75 75
    ///\param gr A digraph.
76 76
    ///\param start The starting point of the tour. If it is not given
77 77
    ///       the tour will start from the first node.
78 78
    DiEulerIt(const GR &gr, typename GR::Node start = INVALID)
79 79
      : g(gr), nedge(g)
80 80
    {
81
      if(start==INVALID) start=NodeIt(g);
82
      for(NodeIt n(g);n!=INVALID;++n) nedge[n]=OutArcIt(g,n);
83
      while(nedge[start]!=INVALID) {
84
        euler.push_back(nedge[start]);
85
        Node next=g.target(nedge[start]);
86
        ++nedge[start];
87
        start=next;
81
      if (start==INVALID) {
82
        NodeIt n(g);
83
        while (n!=INVALID && OutArcIt(g,n)==INVALID) ++n;
84
        start=n;
85
      }
86
      if (start!=INVALID) {
87
        for (NodeIt n(g); n!=INVALID; ++n) nedge[n]=OutArcIt(g,n);
88
        while (nedge[start]!=INVALID) {
89
          euler.push_back(nedge[start]);
90
          Node next=g.target(nedge[start]);
91
          ++nedge[start];
92
          start=next;
93
        }
88 94
      }
89 95
    }
90 96

	
91 97
    ///Arc Conversion
92 98
    operator Arc() { return euler.empty()?INVALID:euler.front(); }
93 99
    bool operator==(Invalid) { return euler.empty(); }
94 100
    bool operator!=(Invalid) { return !euler.empty(); }
95 101

	
96 102
    ///Next arc of the tour
97 103
    DiEulerIt &operator++() {
98 104
      Node s=g.target(euler.front());
99 105
      euler.pop_front();
100 106
      //This produces a warning.Strange.
101 107
      //std::list<Arc>::iterator next=euler.begin();
102 108
      typename std::list<Arc>::iterator next=euler.begin();
103 109
      while(nedge[s]!=INVALID) {
104 110
        euler.insert(next,nedge[s]);
105 111
        Node n=g.target(nedge[s]);
106 112
        ++nedge[s];
107 113
        s=n;
108 114
      }
109 115
      return *this;
110 116
    }
111 117
    ///Postfix incrementation
112 118

	
113 119
    ///\warning This incrementation
114 120
    ///returns an \c Arc, not an \ref DiEulerIt, as one may
115 121
    ///expect.
116 122
    Arc operator++(int)
117 123
    {
118 124
      Arc e=*this;
119 125
      ++(*this);
120 126
      return e;
121 127
    }
122 128
  };
123 129

	
124 130
  ///Euler iterator for graphs.
125 131

	
126 132
  /// \ingroup graph_properties
127 133
  ///This iterator converts to the \c Arc (or \c Edge)
128 134
  ///type of the digraph and using
129 135
  ///operator ++, it provides an Euler tour of an undirected
130 136
  ///digraph (if there exists).
131 137
  ///
132 138
  ///For example
133 139
  ///if the given digraph if Euler (i.e it has only one nontrivial component
134 140
  ///and the degree of each node is even),
135 141
  ///the following code will print the arc IDs according to an
136 142
  ///Euler tour of \c g.
137 143
  ///\code
138 144
  ///  for(EulerIt<ListGraph> e(g),e!=INVALID;++e) {
139 145
  ///    std::cout << g.id(Edge(e)) << std::eol;
140 146
  ///  }
141 147
  ///\endcode
142 148
  ///Although the iterator provides an Euler tour of an graph,
143 149
  ///it still returns Arcs in order to indicate the direction of the tour.
144 150
  ///(But Arc will convert to Edges, of course).
145 151
  ///
146 152
  ///If \c g is not Euler then the resulted tour will not be full or closed.
147 153
  ///\sa EulerIt
148 154
  template<typename GR>
149 155
  class EulerIt
150 156
  {
151 157
    typedef typename GR::Node Node;
152 158
    typedef typename GR::NodeIt NodeIt;
153 159
    typedef typename GR::Arc Arc;
154 160
    typedef typename GR::Edge Edge;
155 161
    typedef typename GR::ArcIt ArcIt;
156 162
    typedef typename GR::OutArcIt OutArcIt;
157 163
    typedef typename GR::InArcIt InArcIt;
158 164

	
159 165
    const GR &g;
160 166
    typename GR::template NodeMap<OutArcIt> nedge;
161 167
    typename GR::template EdgeMap<bool> visited;
162 168
    std::list<Arc> euler;
163 169

	
164 170
  public:
165 171

	
166 172
    ///Constructor
167 173

	
168 174
    ///\param gr An graph.
169 175
    ///\param start The starting point of the tour. If it is not given
170 176
    ///       the tour will start from the first node.
171 177
    EulerIt(const GR &gr, typename GR::Node start = INVALID)
172 178
      : g(gr), nedge(g), visited(g, false)
173 179
    {
174
      if(start==INVALID) start=NodeIt(g);
175
      for(NodeIt n(g);n!=INVALID;++n) nedge[n]=OutArcIt(g,n);
176
      while(nedge[start]!=INVALID) {
177
        euler.push_back(nedge[start]);
178
        visited[nedge[start]]=true;
179
        Node next=g.target(nedge[start]);
180
        ++nedge[start];
181
        start=next;
182
        while(nedge[start]!=INVALID && visited[nedge[start]]) ++nedge[start];
180
      if (start==INVALID) {
181
        NodeIt n(g);
182
        while (n!=INVALID && OutArcIt(g,n)==INVALID) ++n;
183
        start=n;
184
      }
185
      if (start!=INVALID) {
186
        for (NodeIt n(g); n!=INVALID; ++n) nedge[n]=OutArcIt(g,n);
187
        while(nedge[start]!=INVALID) {
188
          euler.push_back(nedge[start]);
189
          visited[nedge[start]]=true;
190
          Node next=g.target(nedge[start]);
191
          ++nedge[start];
192
          start=next;
193
          while(nedge[start]!=INVALID && visited[nedge[start]]) ++nedge[start];
194
        }
183 195
      }
184 196
    }
185 197

	
186 198
    ///Arc Conversion
187 199
    operator Arc() const { return euler.empty()?INVALID:euler.front(); }
188 200
    ///Arc Conversion
189 201
    operator Edge() const { return euler.empty()?INVALID:euler.front(); }
190 202
    ///\e
191 203
    bool operator==(Invalid) const { return euler.empty(); }
192 204
    ///\e
193 205
    bool operator!=(Invalid) const { return !euler.empty(); }
194 206

	
195 207
    ///Next arc of the tour
196 208
    EulerIt &operator++() {
197 209
      Node s=g.target(euler.front());
198 210
      euler.pop_front();
199 211
      typename std::list<Arc>::iterator next=euler.begin();
200 212

	
201 213
      while(nedge[s]!=INVALID) {
202 214
        while(nedge[s]!=INVALID && visited[nedge[s]]) ++nedge[s];
203 215
        if(nedge[s]==INVALID) break;
204 216
        else {
205 217
          euler.insert(next,nedge[s]);
206 218
          visited[nedge[s]]=true;
207 219
          Node n=g.target(nedge[s]);
208 220
          ++nedge[s];
209 221
          s=n;
210 222
        }
211 223
      }
212 224
      return *this;
213 225
    }
214 226

	
215 227
    ///Postfix incrementation
216 228

	
217 229
    ///\warning This incrementation
218 230
    ///returns an \c Arc, not an \ref EulerIt, as one may
219 231
    ///expect.
220 232
    Arc operator++(int)
221 233
    {
222 234
      Arc e=*this;
223 235
      ++(*this);
224 236
      return e;
225 237
    }
226 238
  };
227 239

	
228 240

	
229 241
  ///Checks if the graph is Eulerian
230 242

	
231 243
  /// \ingroup graph_properties
232 244
  ///Checks if the graph is Eulerian. It works for both directed and undirected
233 245
  ///graphs.
234 246
  ///\note By definition, a digraph is called \e Eulerian if
235 247
  ///and only if it is connected and the number of its incoming and outgoing
236 248
  ///arcs are the same for each node.
237 249
  ///Similarly, an undirected graph is called \e Eulerian if
238 250
  ///and only if it is connected and the number of incident arcs is even
239 251
  ///for each node. <em>Therefore, there are digraphs which are not Eulerian,
240 252
  ///but still have an Euler tour</em>.
241 253
  template<typename GR>
242 254
#ifdef DOXYGEN
243 255
  bool
244 256
#else
245 257
  typename enable_if<UndirectedTagIndicator<GR>,bool>::type
246 258
  eulerian(const GR &g)
247 259
  {
248 260
    for(typename GR::NodeIt n(g);n!=INVALID;++n)
249 261
      if(countIncEdges(g,n)%2) return false;
250 262
    return connected(g);
251 263
  }
252 264
  template<class GR>
253 265
  typename disable_if<UndirectedTagIndicator<GR>,bool>::type
254 266
#endif
255 267
  eulerian(const GR &g)
256 268
  {
257 269
    for(typename GR::NodeIt n(g);n!=INVALID;++n)
258 270
      if(countInArcs(g,n)!=countOutArcs(g,n)) return false;
259 271
    return connected(Undirector<const GR>(g));
260 272
  }
261 273

	
262 274
}
263 275

	
264 276
#endif
0 comments (0 inline)