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

An̲*_*rew 274 c++ stl vector range

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

如果使用向量无法有效地完成此操作,是否应该使用另一种STL数据类型?

Gre*_*ers 343

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

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

  • @orip嗯,那么它毕竟是O(N). (63认同)
  • @GregRogers:使用big-O表示法是没有意义的,其中N是一个特定的数字.Big-O传达了N的变化速度.约翰:最好不要以两种方式使用一个变量名.我们通常会说"O(YX)",或者我们说"O(Z),其中Z = YX". (52认同)
  • 为什么不只是`vector <T> newVec(myVec.begin()+ 100000,myVec.begin()+ 101000);`? (12认同)
  • +1,也是O(YX),小于或等于O(N)(在他的例子中少得多) (10认同)
  • @GregRogers通过这种方式,我们需要声明一个新的向量.有没有办法改变原始矢量?像myVec(第一个,最后一个)?我知道这是错的,但我真的需要解决方案,因为我想在我的代码中使用递归,并且需要重复使用相同的向量(虽然已更改).谢谢! (2认同)
  • 另外,如果`newVec` 已经存在并且你想替换它的内容,使用`newVec.asign(first, last)`。它与答案中的构造函数具有相同的语义。 (2认同)
  • 你也可以使用 `auto` 代替 `vector&lt;T&gt;::const_iterator` (2认同)

Mar*_*ork 84

只需使用向量构造函数.

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

std::vector<int>   sub(&data[100000],&data[101000]);
Run Code Online (Sandbox Code Playgroud)

  • @j_random_hacker:抱歉,不得不反对.std :: vector的STL规范已明确更改为支持此类过程.指针也是有效的迭代器类型.查找iterator_traits <> (30认同)
  • 获取这些向量元素的地址是一个不可移植的hack,如果向量存储实际上不是连续的,它将会中断.使用begin()+ 100000等. (5认同)
  • @ taktak004不.请记住`operator []`返回一个引用.只有在您读取或写入引用时才会成为访问冲突.既然我们都没有,而是得到了我们没有调用UB的地址. (4认同)
  • 好的,我没有意识到从任意向量元素中获得迭代器是如此简单。 (2认同)
  • 我的坏,显然标准保证了矢量存储是连续的.然而,使用这样的地址是不好的做法,因为它肯定不能保证适用于支持随机访问的所有容器,而begin()+ 100000则是. (2认同)
  • @bialix:会的。我假设您正在谈论获取过去的地址,然后最终成为问题。这是标准涵盖的并且是允许的。取消引用此地址但不获取其地址是UB。注意`X[Y]`的定义在标准中定义为`*(X + Y)`。并且放在一起的运算符 `&amp;*` 会相互抵消(假设它们没有被覆盖(它们不能用于指针))。=&gt; `&amp;X[Y]` =&gt; `&amp;*(X + Y)` =&gt; `(X + Y)`。这也是为什么 `10000[data]` 是数组访问的有效表达式的原因。 (2认同)

Dav*_*óth 29

这个讨论已经很老了,但最简单的一个还没有提到,列表初始化

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

它需要 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;
}
Run Code Online (Sandbox Code Playgroud)

结果:

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;
Run Code Online (Sandbox Code Playgroud)


Ant*_*eru 24

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

  • 是的,当然,但是你输入std :: vector <int> foo = std :: vector(...)或std :: vector <int> foo(...)应该无关紧要. (3认同)

ein*_*ica 13

这几天,我们用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);
Run Code Online (Sandbox Code Playgroud)

得到1000个与myvecs 相同类型的元素.现在,这不是副本,它只是向量中的数据视图,所以要小心.如果你想要一个实际的副本,你可以这样做:

std::vector<T> new_vec(my_subspan.cbegin(), my_subspan.cend());
Run Code Online (Sandbox Code Playgroud)

笔记:


Ecl*_*pse 10

如果两者都不会被修改(不添加/删除项目-修改现有的罚款,只要你留意线程问题),你可以简单地绕过data.begin() + 100000data.begin() + 101000,假装他们是begin()end()一个较小的载体.

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

T *arrayOfT = &data[0] + 100000;
size_t arrayOfTLength = 1000;
Run Code Online (Sandbox Code Playgroud)

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


Mas*_*rHD 6

你没有提到什么类型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
Run Code Online (Sandbox Code Playgroud)

  • 我想知道是否使用-O3,@ Anteru的"使用构造函数"`std :: vector(myVec.begin()+ 100000,myVec.begin()+ 150000);`,这个产品的较长版本不会准确同样的集会? (2认同)

Mat*_*ade 5

你可以用 insert

vector<type> myVec { n_elements };

vector<type> newVec;

newVec.insert(newVec.begin(), myVec.begin() + X, myVec.begin() + Y);
Run Code Online (Sandbox Code Playgroud)