Since you tried the swap-two approach, let's go back to the problem of
realizing the rotation. First observe, that a std::list is capable of
doing the remove-reinsert operation in constant time. What is the tricky
part is two choose the two positions (std::list::iterator) for the
rotation. What about using a std::vector just for that purpose. So:
std::list< city > route;
std::vector< route::iterator > selector;
You have to initialize the route to go through all the cities and then
you initialize the selector with iterators into the route. Now, removing
an item will invalidate that iterator but it will leave all others valid.
Thus, you need to update that point in the selector after obtaining a new
iterator after re-inserting the selected city.
Best
Kai-Uwe Bux
Hi,
Mmmm ...
If, at the beginning route is: t0 -> t1 -> t2 -> t3.
Then selector[0] = it0, selector[1] = it1, selector[2] = it2, ...
If I remove t0 and put it elsewhere at the end for example, then
selector[0] is invalid but selector[1] will still contain it1,
selector[2]; it2 ...
So selector is not so trivial to manage no ?
I was thinking of something like this:
#include <list>
#include <vector>
#include <cassert>
#include <iostream>
#include <ostream>
#include <iterator>
class route {
public:
typedef unsigned int city;
private:
typedef std::list< city > tour;
typedef tour::iterator site;
typedef std::vector< site > site_seq;
tour the_tour;
site_seq the_site_seq;
public:
route ( unsigned int num_cities )
: the_tour ()
, the_site_seq ()
{
for ( city c = 0; c < num_cities; ++c ) {
site next = the_tour.insert( the_tour.end(), c );
the_site_seq.push_back( next );
assert( c == * the_site_seq[c] );
}
}
template < typename OutIter >
OutIter write_tour ( OutIter where ) const {
return( std::copy( the_tour.begin(), the_tour.end(), where ) );
}
route & move_city ( city moving, city target ) {
site moving_site = the_site_seq[ moving ];
assert( moving == *moving_site );
site target_site = the_site_seq[ target ];
assert( target == *target_site );
the_tour.erase( moving_site );
moving_site = the_tour.insert( target_site, moving );
the_site_seq[ moving ] = moving_site;
}
};
int main ( void ) {
route::city const new_york = 0;
route::city const chicago = 1;
route::city const syracuse = 2;
route::city const salt_lake = 3;
route::city const num_cities = 4;
route the_route ( num_cities );
the_route.write_tour
( std:
stream_iterator< route::city >( std::cout, " " ) );
std::cout << "\n";
the_route.move_city( new_york, salt_lake );
the_route.write_tour
( std:
stream_iterator< route::city >( std::cout, " " ) );
std::cout << "\n";
the_route.move_city( chicago, new_york );
the_route.write_tour
( std:
stream_iterator< route::city >( std::cout, " " ) );
std::cout << "\n";
}
Note: you can place any city in front of any other city in constant time.
However, you reference the cities by a unique id not by their current
position in the tour.
Best
Kai-Uwe Bux