我有两个STL向量A和B,需要将它们合并到第三个,其中元素应该以某种方式排序,输出向量中的每个第n个元素应该是向量B.我当前的代码看起来像什么像这样:
std::vector<int> a(10, 4);
std::vector<int> b(10, 8);
std::vector<int> c;
static const std::size_t STEP(3);
std::vector<int>::const_iterator bIt = b.begin();
for(std::vector<int>::const_iterator aIt = a.begin();
aIt != a.end(); ++aIt)
{
c.push_back(*aIt);
if((c.size() + 1) % STEP == 0)
{
c.push_back(*bIt);
++bIt; //assume b is large enough
}
}
矢量c现在看起来像: 4 4 8 4 4 8 ...
这很好用,但我很好奇是否有更优雅的解决方案。有没有办法使用STL算法而不是我的手写循环?
答案 0 :(得分:1)
这太专业了,不能由<algorithm>
直接涵盖。避免循环将需要自定义迭代器。
template< typename I1, typename I2 >
struct interleave_iterator
: std::iterator< forward_iterator_tag, typename I1::value_type > {
using typename I1::value_type;
I1 i1;
I2 i2;
size_t cnt, stride;
interleave_iterator( I1 in1, I2 in2, size_t in_stride=0, size_t in_off=0 )
: i1( in1 ), i2( in2 ), cnt( in_off ), stride( in_stride ) {}
value_type &operator*() const { return cnt? * i1 : * i2; }
interleave_iterator &operator++() {
if ( ++ cnt == stride ) {
cnt = 0;
++ i2;
} else ++ i1;
return *this;
}
value_type *operator->() const
{ return cnt? i1.operator->() : i2.operator->(); }
interleave_iterator &operator++(int)
{ interleave_iterator r = *this; ++ *this; return r; }
friend bool operator==
( interleave_iterator const &lhs, interleave_iterator const &rhs )
{ return lhs.i1 == rhs.i1 && lhs.i2 == rhs.i2; }
friend bool operator!=
( interleave_iterator const &lhs, interleave_iterator const &rhs )
{ return ! ( lhs == rhs ); }
};
有点过分了,我想。
答案 1 :(得分:1)
我必须承认我非常喜欢Potatoswatter解决方案......非常。
正如他所展示的,这不是算法问题,而是迭代问题。然而,他的解决方案并不适合该法案,因为测试迭代的end
非常困难:它需要非常小心地准备容器和创建迭代器以避免未定义的行为。
我认为使用与迭代器非常相似的概念可以更好地表达问题:views。
视图是一个或多个容器上的Adapter接口。它实际上并不包含任何东西(这是重要的部分)。但它会公开一个类似于容器的界面,以便您可以使用通常的习语进行编码。
关于观点的美好事物是,你经常可以创作它们。
例如,一个非常简单的观点:
/// Only allow to see a range of the container:
/// std::vector<int> v(40, 3); // { 3, 3, 3, ... }
/// auto rv = make_range_view(v, 4, 5);
/// rv exposes the elements in the range [4,9)
/// in debug mode, asserts that the range is sufficiently large
template <typename Container>
class range_view
{
};
对于您的问题,您宁愿创建interleave_view
:
/// Allow to interleave elements of 2 containers each at its own pace
/// std::vector<int> v(40, 3);
/// std::set<int> s = /**/;
///
/// auto iv = make_interleave_view(v, 3, s, 1);
/// Takes 3 elements from v, then 1 from s, then 3 from v, etc...
template <typename C1, typename C2>
class interleave_view
{
};
这里结束迭代器的问题在某种程度上得到缓解,因为我们知道两个容器,因此我们能够自己创建迭代器,确保我们传递适当的参数。
当然,如果容器没有提供有效的“大小”成员(list
没有,那就是O(n)),这会变得有点单调乏味。
然而,一般原则是视图为您提供了更多控制(并允许更多检查),并且使用起来更安全,因为您可以精确控制迭代器的创建。
请注意,在C ++ 0x中,interleave_view
通常会容纳无限数量的序列。