350

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

如果这不能用向量有效地完成,我应该使用另一种 STL 数据类型吗?

4

15 回答 15

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

构造新向量是一个 O(N) 操作,但实际上没有更好的方法。

于 2009-01-07T19:04:54.513 回答
102

只需使用向量构造函数。

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

std::vector<int>   sub(&data[100000],&data[101000]);
于 2009-01-07T19:14:47.300 回答
39

这个讨论已经很老了,但是最简单的还没有提到,使用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;
于 2019-11-06T06:47:01.127 回答
31

这些天来,我们使用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获得与's相同类型的 1000 个元素的跨度。或者更简洁的形式:

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

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

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

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

笔记:

  • gsl代表指南支持库。有关 的更多信息gsl,请参阅:http ://www.modernescpp.com/index.php/c-core-guideline-the-guidelines-support-library 。
  • 有几种gsl实现方式。例如:https ://github.com/martinmoene/gsl-lite
  • C++20 提供了span. 您将使用std::spanand#include <span>而不是#include <gsl/span>.
  • 有关跨度的更多信息,请参阅:什么是“跨度”以及何时应该使用跨度?
  • std::vector有无数的构造函数,很容易陷入你不打算使用的构造函数中,所以要小心。
于 2017-08-09T13:16:10.343 回答
29

std::vector<T>(input_iterator, input_iterator),在您的情况下,请参见此处foo = std::vector<T>(myVec.begin () + 100000, myVec.begin () + 150000);的示例

于 2009-01-07T19:04:46.197 回答
11

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

或者,由于向量存储保证是连续的,您可以简单地传递一个 1000 项数组:

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

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

于 2009-01-07T19:26:37.870 回答
6

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

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
于 2015-10-16T02:03:14.890 回答
5

你可以使用insert

vector<type> myVec { n_elements };

vector<type> newVec;

newVec.insert(newVec.begin(), myVec.begin() + X, myVec.begin() + Y);
于 2019-06-10T00:27:45.283 回答
3

当 M 是子向量的大小时,您可以使用具有 O(M) 性能的STL 复制。

于 2009-01-07T19:03:48.150 回答
1

投影非线性时间集合的唯一方法是懒惰地这样做,其中生成的“向量”实际上是委托给原始集合的子类型。例如,Scala 的List#subseq方法在恒定时间内创建一个子序列。但是,这仅在集合是不可变的并且基础语言支持垃圾收集的情况下才有效。

于 2009-01-07T19:06:30.203 回答
1

假设有两个向量。

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

方法 1. 使用复制功能。copy(first_iterator_index, last_iterator_index, back_inserter()) :- 这个函数有 3 个参数,首先是旧向量的第一个迭代器。其次,旧向量的最后一个迭代器和第三个是 back_inserter 函数,用于从后面插入值。

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

方法 2. 通过使用分配功能。分配(first_iterator_o,last_iterator_o)。此方法为新向量分配与旧向量相同的值。这需要 2 个参数,第一个迭代器到旧向量,最后一个迭代器到旧向量。

    //Copying vector by assign function
    vect2.assign(vect1.begin(), vect1.end());
于 2021-11-15T02:13:03.167 回答
0

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

这也是一个单一的文件实现:array_view

于 2017-04-27T07:36:01.240 回答
0

将元素从一个向量轻松复制到另一个向量
在此示例中,我使用成对向量以使其易于
理解

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)]

'
如您所见,您可以轻松地将元素从一个向量复制到另一个向量,例如,如果您想将元素从索引 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

于 2018-06-24T05:25:54.923 回答
0

还有一个选项:例如在 athrust::device_vector和 a之间移动时很有用thrust::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));
于 2018-06-29T20:22:38.913 回答
-2

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

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

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

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

于 2013-11-18T20:06:07.077 回答