// 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
s分类到原始容器中。然后,我们创建一个临时的容器,东西琐碎value_type
s转换它,swap
那些琐碎value_type
s的从原来的容器正确的数据(如排序iterator
S的vector
确定),然后swap
我们原来的容器这个临时容器。
有很多分配,但希望便宜的东西。
为了达到这个目的,您正在排序的数据需要进行微不足道的构造。为了提高效率,当你使用简单构建的数据需要很便宜,并且需要高效的数据。
我试图让ADL尽可能友好,因为我觉得这是一个很好的习惯。
选中此项:http://stackoverflow.com/questions/13791458/how-to-stable-sort-without-copying/ 如果允许默认构建,解决方案要简单得多。 –
这可能听起来像一个愚蠢的问题,但它是强制性的原始*矢量*排序?我的意思是,例如,你可以建立一个引用向量,并根据你的原始排序标准对* *进行排序,将它用于排序结果的任何恶意目的,同时保持原始向量处于常量状态?可能不会,但如果你没有考虑到它,至少值得思考。 – WhozCraig
@AndreiTita你是对的,而且这种做法迂回地回答了这个问题。但是,由于使用移动语义,这可以用几行代码完成,我希望它也可以直接使用一些奇怪的模板欺骗来完成。 –