// C++03 solution won't work with arrays and some other custom containers.
// Mostly drop this block:
#include <type_traits>
#include <vector>
#include <algorithm>
#include <iostream>
namespace aux {
using std::begin; using std::end;
template<typename C> auto adl_begin( C&& c )->decltype( begin(c) );
template<typename C> auto adl_end( C&& c )->decltype( end(c) );
template<typename C>
struct container_traits:
std::iterator_traits< typename std::decay< decltype( aux::adl_begin( *(C*)nullptr ) ) >::type >
{
typedef typename std::decay< decltype( adl_begin( *(C*)nullptr ) ) >::type iterator_type;
};
}
// C++03 solution won't work with arrays. Inside std::less, use Container::value_type:
template<
typename Container,
typename Comparison = std::less<
typename aux::container_traits<Container>::value_type
>
>
void indirect_sort_then_swap( Container& c, Comparison&& comp = Comparison() ) {
typedef aux::container_traits<Container> con_traits;
typedef typename con_traits::value_type value_type;
typedef typename con_traits::iterator_type iterator_type;
std::vector< iterator_type > indirect;
{
// C++03 solution can use c.begin(), but will not work with arrays:
using std::begin; using std::end;
auto begin_ = begin(c);
auto end_ = end(c);
for( auto it = begin_; it != end_; ++it ) {
indirect.push_back( it );
}
}
// In C++03, write a functor class that does this:
auto indirect_sort = [&comp]( iterator_type const& left, iterator_type const& right )->bool {
return comp(*left, *right);
};
std::sort( indirect.begin(), indirect.end(), indirect_sort );
// at this point, indirect is a vector with the contents of c sorted by iterator:
// a hard part remains, namely to take this information and sort c with minimal swaps
// That is hard. I will instead create an easy approach, namely create an empty
// copy of c full of empty elements, and directly swap the correct entry of c into
// each slot, then I swap c with its copy.
// the downside is that my container now needs to support push_back. Oh well.
Container c2;
// C++03 solution cannot use auto here. But we know the type of indirect:
for (auto it = indirect.begin(); it != indirect.end(); ++it) {
// See previous comment
auto itv = *it;
c2.push_back( value_type() );
using std::swap;
swap( *itv, c2.back() );
}
// by this point, the contents of c have been swap-moved to c2
// swap them back:
{
using std::swap;
swap( c, c2 );
}
}
int main() {
std::vector<int> foo;
foo.push_back(7);
foo.push_back(3);
indirect_sort_then_swap(foo);
for (auto i:foo) {
std::cout << i << "\n";
}
}
上記のようなものは実行可能なアプローチです。私はそれをC++11でたくさん書きましたが、余分なC ++ 11のものを取り除く方法についてのコメントを含めました(実際にはコードを単純化する場合もありますが、コンテナーのようなものを処理する機能を削除します)。
vector
基本的な考え方は、のiterator
を元のコンテナにソートすることです。次に、一時コンテナを作成しvalue_type
、その中に些細なものを詰め込みます。これらのswap
些細なものvalue_type
には、元のコンテナからの正しいデータ(vector
並べ替えられたのによって決定されるiterator
)が含まれ、次にswap
この一時的なコンテナが元のコンテナに使用されます。
割り当てはたくさんありますが、うまくいけば安いものです。
これが機能するためには、ソートするデータが簡単に構築できる必要があります。これを効率的にするには、自明に構築されたときに使用するデータが安価であり、swap
効率的である必要があります。
私はこれをできるだけADLに適したものにしようとしました。これは、良い習慣だと思ったからです。