假设我有一个std::vector
(myVec
大小)N
。构造一个由元素X到Y的副本组成的新矢量的最简单方法是什么,其中0 <= X <= Y <= N-1?例如,myVec [100000]
通过myVec [100999]
一个size的向量150000
。
如果使用向量无法有效完成此操作,是否应该使用另一种STL数据类型呢?
假设我有一个std::vector
(myVec
大小)N
。构造一个由元素X到Y的副本组成的新矢量的最简单方法是什么,其中0 <= X <= Y <= N-1?例如,myVec [100000]
通过myVec [100999]
一个size的向量150000
。
如果使用向量无法有效完成此操作,是否应该使用另一种STL数据类型呢?
Answers:
vector<T>::const_iterator first = myVec.begin() + 100000;
vector<T>::const_iterator last = myVec.begin() + 101000;
vector<T> newVec(first, last);
构造新向量是O(N)操作,但实际上没有更好的方法。
O(Y-X)
,或者我们会说O(Z) where Z=Y-X
。
vector<T> newVec(myVec.begin() + 100000, myVec.begin() + 101000);
呢?
只需使用向量构造函数即可。
std::vector<int> data();
// Load Z elements into data so that Z > Y > X
std::vector<int> sub(&data[100000],&data[101000]);
operator[]
返回一个参考。只有在您读取或写入参考文献的时候,它才会成为访问冲突。由于我们既不执行任何操作,而是获取地址,因此我们尚未调用UB ,。
std::vector<T>(input_iterator, input_iterator)
,以您的情况foo = std::vector<T>(myVec.begin () + 100000, myVec.begin () + 150000);
为例,请参见此处
这些天,我们使用span
s!所以你会写:
#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);
以获取与类型相同的1000个元素的跨度myvec
。或更简洁的形式:
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/Microsoft/GSLspan
。您将使用std::span
和#include <span>
而不是#include <gsl/span>
。std::vector
有大量的构造函数,很容易陷入您不打算使用的结构,所以要小心。cbegin
和cend
仅用于原则;)std::cbegin
等。
如果两个都不会被修改(没有添加/删除项目-修改现有的项目就可以了,只要您注意线程问题),您可以简单地绕过data.begin() + 100000
and data.begin() + 101000
,并假装它们是较小向量的begin()
和end()
。
或者,由于向量存储被保证是连续的,因此您可以简单地传递1000个项目数组:
T *arrayOfT = &data[0] + 100000;
size_t arrayOfTLength = 1000;
这两种技术都需要固定的时间,但是要求数据的长度不增加,从而触发重新分配。
这个讨论已经很老了,但是最简单的讨论还没有提到,它是通过列表初始化的:
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;
您没有提到什么类型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
std::vector(myVec.begin () + 100000, myVec.begin () + 150000);
将这种农产品的更长版本转换为完全相同的程序集吗?
std::vector<>(iter, iter)
为memmove()
,如果合适的话(如果构造函数是琐碎的,那么对于琐碎的适当定义)。
memcpy
。做一个std::copy
或一个接受范围的构造函数(两个迭代器),编译器和std.library将合谋memcpy
在适当的时候调用。
你可以用 insert
vector<type> myVec { n_elements };
vector<type> newVec;
newVec.insert(newVec.begin(), myVec.begin() + X, myVec.begin() + Y);
当M是子向量的大小时,可以将STL复制与O(M)性能一起使用。
newvec.reserve(10100 - 10000);
。IT绝对是一种选择,从技术上讲,它将起作用。但是,您要推荐哪两个呢?
投影非线性时间集合的唯一方法是懒惰地进行投影,其中生成的“向量”实际上是委托给原始集合的子类型。例如,Scala的List#subseq
方法会在恒定时间内创建一个子序列。但是,这仅在该集合是不可变的并且基础语言使用了垃圾回收时才有效。
复制从一个向量到另一个元素容易
在这个例子中,我使用对的载体,可以很容易地理解
`
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
还有另一种选择:例如在a thrust::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));