从向量中提取子向量的最佳方法是什么?

假设我有一个std::vector(让我们称它为myVec),大小为N。构造一个由元素X到Y的副本组成的新向量的最简单方法是什么,其中0 <= X <= Y <= N-1?例如,myVec [100000]myVec [100999]在一个大小为150000的向量中。

如果这不能有效地用一个向量,是否有另一种STL数据类型,我应该使用代替?

481776 次浏览

当M是子向量的大小时,可以使用具有O(M)性能的STL副本

std::vector<T>(input_iterator, input_iterator),在你的情况下是foo = std::vector<T>(myVec.begin () + 100000, myVec.begin () + 150000);,参见例如在这里

vector<T>::const_iterator first = myVec.begin() + 100000;
vector<T>::const_iterator last = myVec.begin() + 101000;
vector<T> newVec(first, last);

这是一个O(N)运算来构造新的向量,但是没有更好的方法了。

投射一个不是线性时间的集合的唯一方法是惰性地这样做,其中产生的“vector”实际上是委托给原始集合的子类型。例如,Scala的List#subseq方法在常数时间内创建子序列。但是,只有当收集是不可变的并且底层语言支持垃圾收集时,这才有效。

只要使用向量构造函数。

std::vector<int>   data();
// Load Z elements into data so that Z > Y > X


std::vector<int>   sub(&data[100000],&data[101000]);

如果这两个都不会被修改(没有添加/删除项-修改现有项是可以的,只要你注意线程问题),你可以简单地传递data.begin() + 100000data.begin() + 101000,并假装它们是一个更小的向量的begin()end()

或者,因为矢量存储保证是连续的,你可以简单地传递一个1000项数组:

T *arrayOfT = &data[0] + 100000;
size_t arrayOfTLength = 1000;

这两种技术都需要固定的时间,但要求数据长度不增加,从而触发重新分配。

发布这么晚只是为了其他人..我打赌第一个编码器现在已经完成了。 对于简单的数据类型,不需要复制,只需恢复到良好的旧C代码方法

std::vector <int>   myVec;
int *p;
// Add some data here and set start, then
p=myVec.data()+start;

然后将指针p和len传递给任何需要子向量的对象。

Notelen一定是!!len < myVec.size()-start

你没有提到std::vector<...> myVec是什么类型,但如果它是一个简单的类型或结构/类,不包括指针,并且你想要最好的效率,那么你可以做一个直接的内存复制(我认为这将比提供的其他答案更快)。下面是std::vector<type> myVec的一般示例,其中type在本例中为int:

typedef int type; //choose your custom type/struct/class
int iFirst = 100000; //first index to copy
int iLast = 101000; //last index + 1
int iLen = iLast - iFirst;
std::vector<type> newVec;
newVec.resize(iLen); //pre-allocate the space needed to write the data directly
memcpy(&newVec[0], &myVec[iFirst], iLen*sizeof(type)); //write directly to destination buffer from source buffer

也许GSL库中的array_view /跨度是一个不错的选择。

这里还有一个单独的文件实现:array_view

现在,我们使用spans!所以你可以这样写:

#include <gsl/span>


...
auto start_pos = 100000;
auto length = 1000;
auto span_of_myvec = gsl::make_span(myvec);
auto my_subspan = span_of_myvec.subspan(start_pos, length);

来获取与myvec相同类型的1000个元素的span。或者更简洁的形式:

auto my_subspan = gsl::make_span(myvec).subspan(1000000, 1000);

(但我不太喜欢这个,因为每个数字参数的含义并不完全清楚;如果长度和start_pos是同一个数量级,情况会变得更糟。)

不管怎样,记住这是向量中数据的不是拷贝,只是一个视图,所以要小心。如果你想要一个实际的副本,你可以这样做:

std::vector<T> new_vec(my_subspan.cbegin(), my_subspan.cend());

注:

轻松地将元素从一个向量复制到另一个向量
在这个例子中,为了便于理解,我使用了一对向量
' < / p >

vector<pair<int, int> > v(n);


//we want half of elements in vector a and another half in vector b
vector<pair<lli, lli> > a(v.begin(),v.begin()+n/2);
vector<pair<lli, lli> > b(v.begin()+n/2, v.end());




//if v = [(1, 2), (2, 3), (3, 4), (4, 5), (5, 6)]
//then a = [(1, 2), (2, 3)]
//and b = [(3, 4), (4, 5), (5, 6)]


//if v = [(1, 2), (2, 3), (3, 4), (4, 5), (5, 6), (6, 7)]
//then a = [(1, 2), (2, 3), (3, 4)]
//and b = [(4, 5), (5, 6), (6, 7)]
< p > '
正如你所看到的,你可以很容易地将元素从一个向量复制到另一个向量,例如,如果你想从索引10复制到索引16,那么我们可以使用

vector<pair<int, int> > a(v.begin()+10, v.begin+16);

如果你想让元素从索引10到末尾的某个索引,那么在这种情况下

vector<pair<int, int> > a(v.begin()+10, v.end()-5);

希望这有帮助,只要记住在最后一种情况v.end()-5 > v.begin()+10

还有另一个选择: 例如在thrust::device_vectorthrust::host_vector之间移动时很有用,在那里你不能使用构造函数
std::vector<T> newVector;
newVector.reserve(1000);
std::copy_n(&vec[100000], 1000, std::back_inserter(newVector));

复杂度也应该是O(N)

您可以将此与顶部答案代码结合起来

vector<T>::const_iterator first = myVec.begin() + 100000;
vector<T>::const_iterator last = myVec.begin() + 101000;
std::copy(first, last, std::back_inserter(newVector));

你可以直接使用insert

vector<type> myVec { n_elements };


vector<type> newVec;


newVec.insert(newVec.begin(), myVec.begin() + X, myVec.begin() + Y);

这个讨论已经很老了,但最简单的一个还没有提到,即list-initialization:

 vector<int> subvector = {big_vector.begin() + 3, big_vector.end() - 2};

它要求c++11或以上。

使用示例:

#include <iostream>
#include <vector>
#include <algorithm>


using namespace std;


int main(){


vector<int> big_vector = {5,12,4,6,7,8,9,9,31,1,1,5,76,78,8};
vector<int> subvector = {big_vector.begin() + 3, big_vector.end() - 2};


cout << "Big vector: ";
for_each(big_vector.begin(), big_vector.end(),[](int number){cout << number << ";";});
cout << endl << "Subvector: ";
for_each(subvector.begin(), subvector.end(),[](int number){cout << number << ";";});
cout << endl;
}

结果:

Big vector: 5;12;4;6;7;8;9;9;31;1;1;5;76;78;8;
Subvector: 6;7;8;9;9;31;1;1;5;76;

假设有两个向量。

 vector<int> vect1{1, 2, 3, 4};
vector<int> vect2;

方法1。使用拷贝功能。copy(first_iterator_index, last_iterator_index, back_inserter()):-该函数有3个参数,首先,旧vector的第一个迭代器。其次,old vector的最后一个迭代器和第三个迭代器是back_inserter函数,用于从back插入值。

    // Copying vector by copy function
copy(vect1.begin(), vect1.end(), back_inserter(vect2));

方法2。通过使用赋值函数。分配(first_iterator_o last_iterator_o)。该方法将相同的值赋给新向量和旧向量。它有两个参数,第一个迭代器指向旧向量,最后一个迭代器指向旧向量。

    //Copying vector by assign function
vect2.assign(vect1.begin(), vect1.end());

vector::assign可能是另一个解决方案

// note: size1 < src.size() && size2 < src.size()
std::vector<int> sub1(size1), sub2(size2);
sub1.assign(src.begin(), src.begin() + size1);
sub2.assign(src.begin(), src.begin() + size2);