Changeset 750:bb3392fe91f2 in lemon for lemon/binom_heap.h
 Timestamp:
 07/09/09 04:07:08 (10 years ago)
 Branch:
 default
 Phase:
 public
 File:

 1 edited
Legend:
 Unmodified
 Added
 Removed

lemon/binom_heap.h
r748 r750 1 /* * C++*1 /* * mode: C++; indenttabsmode: nil; * 2 2 * 3 * This file is a part of LEMON, a generic C++ optimization library 3 * This file is a part of LEMON, a generic C++ optimization library. 4 4 * 5 * Copyright (C) 2003200 85 * Copyright (C) 20032009 6 6 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport 7 7 * (Egervary Research Group on Combinatorial Optimization, EGRES). … … 21 21 22 22 ///\file 23 ///\ingroup auxdat23 ///\ingroup heaps 24 24 ///\brief Binomial Heap implementation. 25 25 26 26 #include <vector> 27 #include <utility> 27 28 #include <functional> 28 29 #include <lemon/math.h> … … 31 32 namespace lemon { 32 33 33 /// \ingroup auxdat34 /// \ingroup heaps 34 35 /// 35 ///\brief Binomial Heap.36 ///\brief Binomial heap data structure. 36 37 /// 37 ///This class implements the \e Binomial \e heap data structure. A \e heap 38 ///is a data structure for storing items with specified values called \e 39 ///priorities in such a way that finding the item with minimum priority is 40 ///efficient. \c Compare specifies the ordering of the priorities. In a heap 41 ///one can change the priority of an item, add or erase an item, etc. 38 /// This class implements the \e binomial \e heap data structure. 39 /// It fully conforms to the \ref concepts::Heap "heap concept". 42 40 /// 43 ///The methods \ref increase and \ref erase are not efficient in a Binomial 44 ///heap. In case of many calls to these operations, it is better to use a 45 ///\ref BinHeap "binary heap". 41 /// The methods \ref increase() and \ref erase() are not efficient 42 /// in a binomial heap. In case of many calls of these operations, 43 /// it is better to use other heap structure, e.g. \ref BinHeap 44 /// "binary heap". 46 45 /// 47 ///\param _Prio Type of the priority of the items. 48 ///\param _ItemIntMap A read and writable Item int map, used internally 49 ///to handle the cross references. 50 ///\param _Compare A class for the ordering of the priorities. The 51 ///default is \c std::less<_Prio>. 52 /// 53 ///\sa BinHeap 54 ///\sa Dijkstra 55 ///\author Dorian Batha 56 46 /// \tparam PR Type of the priorities of the items. 47 /// \tparam IM A readwritable item map with \c int values, used 48 /// internally to handle the cross references. 49 /// \tparam CMP A functor class for comparing the priorities. 50 /// The default is \c std::less<PR>. 57 51 #ifdef DOXYGEN 58 template <typename _Prio, 59 typename _ItemIntMap, 60 typename _Compare> 52 template <typename PR, typename IM, typename CMP> 61 53 #else 62 template <typename _Prio, 63 typename _ItemIntMap, 64 typename _Compare = std::less<_Prio> > 54 template <typename PR, typename IM, typename CMP = std::less<PR> > 65 55 #endif 66 56 class BinomHeap { 67 57 public: 68 typedef _ItemIntMap ItemIntMap; 69 typedef _Prio Prio; 58 /// Type of the itemint map. 59 typedef IM ItemIntMap; 60 /// Type of the priorities. 61 typedef PR Prio; 62 /// Type of the items stored in the heap. 70 63 typedef typename ItemIntMap::Key Item; 71 typedef std::pair<Item,Prio> Pair; 72 typedef _Compare Compare; 64 /// Functor type for comparing the priorities. 65 typedef CMP Compare; 66 67 /// \brief Type to represent the states of the items. 68 /// 69 /// Each item has a state associated to it. It can be "in heap", 70 /// "preheap" or "postheap". The latter two are indifferent from the 71 /// heap's point of view, but may be useful to the user. 72 /// 73 /// The itemint map must be initialized in such way that it assigns 74 /// \c PRE_HEAP (<tt>1</tt>) to any element to be put in the heap. 75 enum State { 76 IN_HEAP = 0, ///< = 0. 77 PRE_HEAP = 1, ///< = 1. 78 POST_HEAP = 2 ///< = 2. 79 }; 73 80 74 81 private: 75 82 class store; 76 83 77 std::vector<store> container;78 int minimum,head;79 ItemIntMap & iimap;80 Compare comp;81 int num_items;84 std::vector<store> _data; 85 int _min, _head; 86 ItemIntMap &_iim; 87 Compare _comp; 88 int _num_items; 82 89 83 90 public: 84 ///Status of the nodes 85 enum State { 86 ///The node is in the heap 87 IN_HEAP = 0, 88 ///The node has never been in the heap 89 PRE_HEAP = 1, 90 ///The node was in the heap but it got out of it 91 POST_HEAP = 2 92 }; 93 94 /// \brief The constructor 95 /// 96 /// \c _iimap should be given to the constructor, since it is 97 /// used internally to handle the cross references. 98 explicit BinomHeap(ItemIntMap &_iimap) 99 : minimum(0), head(1), iimap(_iimap), num_items() {} 100 101 /// \brief The constructor 102 /// 103 /// \c _iimap should be given to the constructor, since it is used 104 /// internally to handle the cross references. \c _comp is an 105 /// object for ordering of the priorities. 106 BinomHeap(ItemIntMap &_iimap, const Compare &_comp) 107 : minimum(0), head(1), iimap(_iimap), comp(_comp), num_items() {} 91 /// \brief Constructor. 92 /// 93 /// Constructor. 94 /// \param map A map that assigns \c int values to the items. 95 /// It is used internally to handle the cross references. 96 /// The assigned value must be \c PRE_HEAP (<tt>1</tt>) for each item. 97 explicit BinomHeap(ItemIntMap &map) 98 : _min(0), _head(1), _iim(map), _num_items(0) {} 99 100 /// \brief Constructor. 101 /// 102 /// Constructor. 103 /// \param map A map that assigns \c int values to the items. 104 /// It is used internally to handle the cross references. 105 /// The assigned value must be \c PRE_HEAP (<tt>1</tt>) for each item. 106 /// \param comp The function object used for comparing the priorities. 107 BinomHeap(ItemIntMap &map, const Compare &comp) 108 : _min(0), _head(1), _iim(map), _comp(comp), _num_items(0) {} 108 109 109 110 /// \brief The number of items stored in the heap. 110 111 /// 111 /// Returns the number of items stored in the heap. 112 int size() const { return num_items; } 113 114 /// \brief Checks if the heap stores no items. 115 /// 116 /// Returns \c true if and only if the heap stores no items. 117 bool empty() const { return num_items==0; } 118 119 /// \brief Make empty this heap. 120 /// 121 /// Make empty this heap. It does not change the cross reference 122 /// map. If you want to reuse a heap what is not surely empty you 123 /// should first clear the heap and after that you should set the 124 /// cross reference map for each item to \c PRE_HEAP. 112 /// This function returns the number of items stored in the heap. 113 int size() const { return _num_items; } 114 115 /// \brief Check if the heap is empty. 116 /// 117 /// This function returns \c true if the heap is empty. 118 bool empty() const { return _num_items==0; } 119 120 /// \brief Make the heap empty. 121 /// 122 /// This functon makes the heap empty. 123 /// It does not change the cross reference map. If you want to reuse 124 /// a heap that is not surely empty, you should first clear it and 125 /// then you should set the cross reference map to \c PRE_HEAP 126 /// for each item. 125 127 void clear() { 126 container.clear(); minimum=0; num_items=0; head=1; 127 } 128 129 /// \brief \c item gets to the heap with priority \c value independently 130 /// if \c item was already there. 131 /// 132 /// This method calls \ref push(\c item, \c value) if \c item is not 133 /// stored in the heap and it calls \ref decrease(\c item, \c value) or 134 /// \ref increase(\c item, \c value) otherwise. 128 _data.clear(); _min=0; _num_items=0; _head=1; 129 } 130 131 /// \brief Set the priority of an item or insert it, if it is 132 /// not stored in the heap. 133 /// 134 /// This method sets the priority of the given item if it is 135 /// already stored in the heap. Otherwise it inserts the given 136 /// item into the heap with the given priority. 137 /// \param item The item. 138 /// \param value The priority. 135 139 void set (const Item& item, const Prio& value) { 136 int i= iimap[item];137 if ( i >= 0 && container[i].in ) {138 if ( comp(value, container[i].prio) ) decrease(item, value);139 if ( comp(container[i].prio, value) ) increase(item, value);140 int i=_iim[item]; 141 if ( i >= 0 && _data[i].in ) { 142 if ( _comp(value, _data[i].prio) ) decrease(item, value); 143 if ( _comp(_data[i].prio, value) ) increase(item, value); 140 144 } else push(item, value); 141 145 } 142 146 143 /// \brief Adds \c item to the heap with priority \c value. 144 /// 145 /// Adds \c item to the heap with priority \c value. 146 /// \pre \c item must not be stored in the heap. 147 /// \brief Insert an item into the heap with the given priority. 148 /// 149 /// This function inserts the given item into the heap with the 150 /// given priority. 151 /// \param item The item to insert. 152 /// \param value The priority of the item. 153 /// \pre \e item must not be stored in the heap. 147 154 void push (const Item& item, const Prio& value) { 148 int i= iimap[item];155 int i=_iim[item]; 149 156 if ( i<0 ) { 150 int s= container.size();151 iimap.set( item,s );157 int s=_data.size(); 158 _iim.set( item,s ); 152 159 store st; 153 160 st.name=item; 154 container.push_back(st);161 _data.push_back(st); 155 162 i=s; 156 163 } 157 164 else { 158 container[i].parent=container[i].right_neighbor=container[i].child=1;159 container[i].degree=0;160 container[i].in=true;161 } 162 container[i].prio=value;163 164 if( 0== num_items ) { head=i; minimum=i; }165 _data[i].parent=_data[i].right_neighbor=_data[i].child=1; 166 _data[i].degree=0; 167 _data[i].in=true; 168 } 169 _data[i].prio=value; 170 171 if( 0==_num_items ) { _head=i; _min=i; } 165 172 else { merge(i); } 166 173 167 minimum = find_min();168 169 ++ num_items;170 } 171 172 /// \brief Return s the item with minimum priority relative to \c Compare.173 /// 174 /// This method returns the item with minimum priority relative to \c175 /// Compare.176 /// \pre The heap must be nonempty.177 Item top() const { return container[minimum].name; } 178 179 /// \brief Returns the minimum priority relative to \c Compare.180 /// 181 /// It returns the minimum priority relative to \c Compare.182 /// \pre The heap must be nonempty.183 const Prio& prio() const { return container[minimum].prio; } 184 185 /// \brief Returns the priority of \c item.186 /// 187 /// It returns the priority of \citem.188 /// \pre \ citem must be in the heap.174 _min = findMin(); 175 176 ++_num_items; 177 } 178 179 /// \brief Return the item having minimum priority. 180 /// 181 /// This function returns the item having minimum priority. 182 /// \pre The heap must be nonempty. 183 Item top() const { return _data[_min].name; } 184 185 /// \brief The minimum priority. 186 /// 187 /// This function returns the minimum priority. 188 /// \pre The heap must be nonempty. 189 Prio prio() const { return _data[_min].prio; } 190 191 /// \brief The priority of the given item. 192 /// 193 /// This function returns the priority of the given item. 194 /// \param item The item. 195 /// \pre \e item must be in the heap. 189 196 const Prio& operator[](const Item& item) const { 190 return container[iimap[item]].prio; 191 } 192 193 /// \brief Deletes the item with minimum priority relative to \c Compare. 194 /// 195 /// This method deletes the item with minimum priority relative to \c 196 /// Compare from the heap. 197 return _data[_iim[item]].prio; 198 } 199 200 /// \brief Remove the item having minimum priority. 201 /// 202 /// This function removes the item having minimum priority. 197 203 /// \pre The heap must be nonempty. 198 204 void pop() { 199 container[minimum].in=false;205 _data[_min].in=false; 200 206 201 207 int head_child=1; 202 if ( container[minimum].child!=1 ) {203 int child= container[minimum].child;208 if ( _data[_min].child!=1 ) { 209 int child=_data[_min].child; 204 210 int neighb; 205 211 int prev=1; 206 212 while( child!=1 ) { 207 neighb= container[child].right_neighbor;208 container[child].parent=1;209 container[child].right_neighbor=prev;213 neighb=_data[child].right_neighbor; 214 _data[child].parent=1; 215 _data[child].right_neighbor=prev; 210 216 head_child=child; 211 217 prev=child; … … 215 221 216 222 // The first case is that there are only one root. 217 if ( 1== container[head].right_neighbor ) {218 head=head_child;223 if ( 1==_data[_head].right_neighbor ) { 224 _head=head_child; 219 225 } 220 226 // The case where there are more roots. 221 227 else { 222 if( head!=minimum ) { unlace(minimum); }223 else { head=container[head].right_neighbor; }228 if( _head!=_min ) { unlace(_min); } 229 else { _head=_data[_head].right_neighbor; } 224 230 225 231 merge(head_child); 226 232 } 227 minimum=find_min(); 228 num_items; 229 } 230 231 /// \brief Deletes \c item from the heap. 232 /// 233 /// This method deletes \c item from the heap, if \c item was already 234 /// stored in the heap. It is quite inefficient in Binomial heaps. 233 _min=findMin(); 234 _num_items; 235 } 236 237 /// \brief Remove the given item from the heap. 238 /// 239 /// This function removes the given item from the heap if it is 240 /// already stored. 241 /// \param item The item to delete. 242 /// \pre \e item must be in the heap. 235 243 void erase (const Item& item) { 236 int i= iimap[item];237 if ( i >= 0 && container[i].in ) {238 decrease( item, container[minimum].prio1 );244 int i=_iim[item]; 245 if ( i >= 0 && _data[i].in ) { 246 decrease( item, _data[_min].prio1 ); 239 247 pop(); 240 248 } 241 249 } 242 250 243 /// \brief Decreases the priority of \c item to \c value. 244 /// 245 /// This method decreases the priority of \c item to \c value. 246 /// \pre \c item must be stored in the heap with priority at least \c 247 /// value relative to \c Compare. 251 /// \brief Decrease the priority of an item to the given value. 252 /// 253 /// This function decreases the priority of an item to the given value. 254 /// \param item The item. 255 /// \param value The priority. 256 /// \pre \e item must be stored in the heap with priority at least \e value. 248 257 void decrease (Item item, const Prio& value) { 249 int i= iimap[item];250 251 if( comp( value,container[i].prio ) ) {252 container[i].prio=value;253 254 int p_loc= container[i].parent, loc=i;258 int i=_iim[item]; 259 260 if( _comp( value,_data[i].prio ) ) { 261 _data[i].prio=value; 262 263 int p_loc=_data[i].parent, loc=i; 255 264 int parent, child, neighb; 256 265 257 while( 1!=p_loc && comp(container[loc].prio,container[p_loc].prio) ) {266 while( 1!=p_loc && _comp(_data[loc].prio,_data[p_loc].prio) ) { 258 267 259 268 // parent set for other loc_child 260 child= container[loc].child;269 child=_data[loc].child; 261 270 while( 1!=child ) { 262 container[child].parent=p_loc;263 child= container[child].right_neighbor;271 _data[child].parent=p_loc; 272 child=_data[child].right_neighbor; 264 273 } 265 274 266 275 // parent set for other p_loc_child 267 child= container[p_loc].child;276 child=_data[p_loc].child; 268 277 while( 1!=child ) { 269 container[child].parent=loc;270 child= container[child].right_neighbor;271 } 272 273 child= container[p_loc].child;274 container[p_loc].child=container[loc].child;278 _data[child].parent=loc; 279 child=_data[child].right_neighbor; 280 } 281 282 child=_data[p_loc].child; 283 _data[p_loc].child=_data[loc].child; 275 284 if( child==loc ) 276 285 child=p_loc; 277 container[loc].child=child;286 _data[loc].child=child; 278 287 279 288 // left_neighb set for p_loc 280 if( container[loc].child!=p_loc ) {281 while( container[child].right_neighbor!=loc )282 child= container[child].right_neighbor;283 container[child].right_neighbor=p_loc;289 if( _data[loc].child!=p_loc ) { 290 while( _data[child].right_neighbor!=loc ) 291 child=_data[child].right_neighbor; 292 _data[child].right_neighbor=p_loc; 284 293 } 285 294 286 295 // left_neighb set for loc 287 parent= container[p_loc].parent;288 if( 1!=parent ) child= container[parent].child;289 else child= head;296 parent=_data[p_loc].parent; 297 if( 1!=parent ) child=_data[parent].child; 298 else child=_head; 290 299 291 300 if( child!=p_loc ) { 292 while( container[child].right_neighbor!=p_loc )293 child= container[child].right_neighbor;294 container[child].right_neighbor=loc;295 } 296 297 neighb= container[p_loc].right_neighbor;298 container[p_loc].right_neighbor=container[loc].right_neighbor;299 container[loc].right_neighbor=neighb;300 301 container[p_loc].parent=loc;302 container[loc].parent=parent;303 304 if( 1!=parent && container[parent].child==p_loc )305 container[parent].child=loc;301 while( _data[child].right_neighbor!=p_loc ) 302 child=_data[child].right_neighbor; 303 _data[child].right_neighbor=loc; 304 } 305 306 neighb=_data[p_loc].right_neighbor; 307 _data[p_loc].right_neighbor=_data[loc].right_neighbor; 308 _data[loc].right_neighbor=neighb; 309 310 _data[p_loc].parent=loc; 311 _data[loc].parent=parent; 312 313 if( 1!=parent && _data[parent].child==p_loc ) 314 _data[parent].child=loc; 306 315 307 316 /*if new parent will be the first root*/ 308 if( head==p_loc ) 309 head=loc; 310 311 p_loc=container[loc].parent; 312 } 313 } 314 if( comp(value,container[minimum].prio) ) { 315 minimum=i; 316 } 317 } 318 319 /// \brief Increases the priority of \c item to \c value. 320 /// 321 /// This method sets the priority of \c item to \c value. Though 322 /// there is no precondition on the priority of \c item, this 323 /// method should be used only if it is indeed necessary to increase 324 /// (relative to \c Compare) the priority of \c item, because this 325 /// method is inefficient. 317 if( _head==p_loc ) 318 _head=loc; 319 320 p_loc=_data[loc].parent; 321 } 322 } 323 if( _comp(value,_data[_min].prio) ) { 324 _min=i; 325 } 326 } 327 328 /// \brief Increase the priority of an item to the given value. 329 /// 330 /// This function increases the priority of an item to the given value. 331 /// \param item The item. 332 /// \param value The priority. 333 /// \pre \e item must be stored in the heap with priority at most \e value. 326 334 void increase (Item item, const Prio& value) { 327 335 erase(item); … … 329 337 } 330 338 331 332 /// \brief Returns if \c item is in, has already been in, or has never333 /// been in the heap.334 /// 335 /// This method returns PRE_HEAP if \c item has never been in the336 /// heap, IN_HEAP if it is in the heap at the moment, and POST_HEAP337 /// otherwise. In the latter case it is possible that \c item will338 /// get back to the heap again.339 /// \brief Return the state of an item. 340 /// 341 /// This method returns \c PRE_HEAP if the given item has never 342 /// been in the heap, \c IN_HEAP if it is in the heap at the moment, 343 /// and \c POST_HEAP otherwise. 344 /// In the latter case it is possible that the item will get back 345 /// to the heap again. 346 /// \param item The item. 339 347 State state(const Item &item) const { 340 int i= iimap[item];348 int i=_iim[item]; 341 349 if( i>=0 ) { 342 if ( container[i].in ) i=0;350 if ( _data[i].in ) i=0; 343 351 else i=2; 344 352 } … … 346 354 } 347 355 348 /// \brief Set s the state of the \citem in the heap.349 /// 350 /// Sets the state of the \c item in the heap. It can be used to351 /// manually clear the heap when it is important to achive the352 /// better time complexity.356 /// \brief Set the state of an item in the heap. 357 /// 358 /// This function sets the state of the given item in the heap. 359 /// It can be used to manually clear the heap when it is important 360 /// to achive better time complexity. 353 361 /// \param i The item. 354 362 /// \param st The state. It should not be \c IN_HEAP. … … 360 368 erase(i); 361 369 } 362 iimap[i] = st;370 _iim[i] = st; 363 371 break; 364 372 case IN_HEAP: … … 368 376 369 377 private: 370 int find _min() {378 int findMin() { 371 379 int min_loc=1, min_val; 372 int x= head;380 int x=_head; 373 381 if( x!=1 ) { 374 min_val= container[x].prio;382 min_val=_data[x].prio; 375 383 min_loc=x; 376 x= container[x].right_neighbor;384 x=_data[x].right_neighbor; 377 385 378 386 while( x!=1 ) { 379 if( comp( container[x].prio,min_val ) ) {380 min_val= container[x].prio;387 if( _comp( _data[x].prio,min_val ) ) { 388 min_val=_data[x].prio; 381 389 min_loc=x; 382 390 } 383 x= container[x].right_neighbor;391 x=_data[x].right_neighbor; 384 392 } 385 393 } … … 390 398 interleave(a); 391 399 392 int x= head;400 int x=_head; 393 401 if( 1!=x ) { 394 int x_prev=1, x_next= container[x].right_neighbor;402 int x_prev=1, x_next=_data[x].right_neighbor; 395 403 while( 1!=x_next ) { 396 if( container[x].degree!=container[x_next].degree  ( 1!=container[x_next].right_neighbor && container[container[x_next].right_neighbor].degree==container[x].degree ) ) {404 if( _data[x].degree!=_data[x_next].degree  ( 1!=_data[x_next].right_neighbor && _data[_data[x_next].right_neighbor].degree==_data[x].degree ) ) { 397 405 x_prev=x; 398 406 x=x_next; 399 407 } 400 408 else { 401 if( comp(container[x].prio,container[x_next].prio) ) {402 container[x].right_neighbor=container[x_next].right_neighbor;409 if( _comp(_data[x].prio,_data[x_next].prio) ) { 410 _data[x].right_neighbor=_data[x_next].right_neighbor; 403 411 fuse(x_next,x); 404 412 } 405 413 else { 406 if( 1==x_prev ) { head=x_next; }414 if( 1==x_prev ) { _head=x_next; } 407 415 else { 408 container[x_prev].right_neighbor=x_next;416 _data[x_prev].right_neighbor=x_next; 409 417 } 410 418 fuse(x,x_next); … … 412 420 } 413 421 } 414 x_next= container[x].right_neighbor;422 x_next=_data[x].right_neighbor; 415 423 } 416 424 } … … 420 428 int other=1, head_other=1; 421 429 422 while( 1!=a  1!= head ) {430 while( 1!=a  1!=_head ) { 423 431 if( 1==a ) { 424 432 if( 1==head_other ) { 425 head_other= head;433 head_other=_head; 426 434 } 427 435 else { 428 container[other].right_neighbor=head;429 } 430 head=1;431 } 432 else if( 1== head ) {436 _data[other].right_neighbor=_head; 437 } 438 _head=1; 439 } 440 else if( 1==_head ) { 433 441 if( 1==head_other ) { 434 442 head_other=a; 435 443 } 436 444 else { 437 container[other].right_neighbor=a;445 _data[other].right_neighbor=a; 438 446 } 439 447 a=1; 440 448 } 441 449 else { 442 if( container[a].degree<container[head].degree ) {450 if( _data[a].degree<_data[_head].degree ) { 443 451 if( 1==head_other ) { 444 452 head_other=a; 445 453 } 446 454 else { 447 container[other].right_neighbor=a;455 _data[other].right_neighbor=a; 448 456 } 449 457 other=a; 450 a= container[a].right_neighbor;458 a=_data[a].right_neighbor; 451 459 } 452 460 else { 453 461 if( 1==head_other ) { 454 head_other= head;462 head_other=_head; 455 463 } 456 464 else { 457 container[other].right_neighbor=head;465 _data[other].right_neighbor=_head; 458 466 } 459 other= head;460 head=container[head].right_neighbor;461 } 462 } 463 } 464 head=head_other;467 other=_head; 468 _head=_data[_head].right_neighbor; 469 } 470 } 471 } 472 _head=head_other; 465 473 } 466 474 467 475 // Lacing a under b 468 476 void fuse(int a, int b) { 469 container[a].parent=b;470 container[a].right_neighbor=container[b].child;471 container[b].child=a;472 473 ++ container[b].degree;477 _data[a].parent=b; 478 _data[a].right_neighbor=_data[b].child; 479 _data[b].child=a; 480 481 ++_data[b].degree; 474 482 } 475 483 476 484 // It is invoked only if a has siblings. 477 485 void unlace(int a) { 478 int neighb= container[a].right_neighbor;479 int other= head;480 481 while( container[other].right_neighbor!=a )482 other= container[other].right_neighbor;483 container[other].right_neighbor=neighb;486 int neighb=_data[a].right_neighbor; 487 int other=_head; 488 489 while( _data[other].right_neighbor!=a ) 490 other=_data[other].right_neighbor; 491 _data[other].right_neighbor=neighb; 484 492 } 485 493
Note: See TracChangeset
for help on using the changeset viewer.