Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/139.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 创建std::vector减去一个元素的副本的最快方法_C++_Algorithm_Vector_Data Structures_Time Complexity - Fatal编程技术网

C++ 创建std::vector减去一个元素的副本的最快方法

C++ 创建std::vector减去一个元素的副本的最快方法,c++,algorithm,vector,data-structures,time-complexity,C++,Algorithm,Vector,Data Structures,Time Complexity,我有一个std::vector[1,2,3,4,5],我想得到另一个包含所有元素的向量,但第二个元素除外:[1,3,4,5]。一种方法是vec1是我的输入向量: std::vector<int> vec2; vec2 = vec1; vec2.erase(vec2.begin()+1) 在这里,我真的不喜欢擦除,因为它的复杂性,所以考虑到数组的副本,我将有2n个操作。我在想,旧的虚拟方式会更好: std::vector<int> vec2; for(int i=0; i

我有一个std::vector[1,2,3,4,5],我想得到另一个包含所有元素的向量,但第二个元素除外:[1,3,4,5]。一种方法是vec1是我的输入向量:

std::vector<int> vec2;
vec2 = vec1;
vec2.erase(vec2.begin()+1)
在这里,我真的不喜欢擦除,因为它的复杂性,所以考虑到数组的副本,我将有2n个操作。我在想,旧的虚拟方式会更好:

std::vector<int> vec2;
for(int i=0; i<vec1.size(); ++i){
    if (i != 1) 
        vec2.push_back(vec1[i]);
}
这是按时摊销的。渐近行为是相同的,但操作的数量可能更小

我必须在相当小的向量上做这个,大约100个元素,但我有数十亿个元素。我会注意到一个显著的差异吗


你会怎么做

关于复杂性,您无法寻求比On更好的方法,因为您必须复制n个元素。但为了进行一些微观优化,您可以:

事先保留大小,如注释中所示 避免检查循环内的条件,方法是连续复制2次,但不检查:

std::vector<int> vec1 = { 1,2,3,4,5 };
std::vector<int> vec2(vec1.size()-1);

constexpr int i = 1; // let i be the position you want to skip

std::copy(vec1.cbegin(), vec1.cbegin() + i, vec2.begin());
std::copy(vec1.cbegin() + i+1, vec1.cend(), vec2.begin()+i);
因为没有if语句或std::copy if,所以拷贝将是直接的,而且还有很好的编译器优化空间


编辑:如下面的注释所示,调整向量的大小会导致一些额外的初始化,请参阅此处关于避免初始化的方法的讨论:

这可以使用std::vector的现有例程来完成。给定i,您要跳过的位置在vec范围内:

通过保留空间,我们避免了ret中任何不必要的内存分配。vector::insert在最后完成时,不需要移动元素


诚然,insert可能会执行一些超出严格要求的额外条件来检查迭代器的范围是否适合现有存储,但不太可能一系列push_-back调用会更快。如果向量的大小很重要,不必预先初始化数组就可以为自己付费。

这是我能想到的最快的方法:

std::vector<int> vec1{1, 2, 3, 4, 5};

// Do not call the constructor with the known size here. That would allocate
// AND initialize a lot of data that will be overwritten later anyway.
std::vector<int> vec2;

// Instead, use it on 'reserve' since it only allocates the memory and
// leaves it uninitialized. The vector is still considered empty, but its
// underlying capacity will be big enough to be filled with new data
// without any unnecessary initializations and reallocations occuring (as long
// as you don't exceed the capacity)
vec2.reserve(vec1.size() - 1);

// Nothing expensive should be going on behind the scenes now, just fill it up
for(auto it = vec1.begin(), skip = vec1.begin() + 1 ; it != vec1.end() ; ++it) {
    if(it != skip) {
        vec2.push_back(*it);
    }
}

先打电话预约。至于你是否会注意到其中的差异,那么请描述一下,这是获得可靠答案的唯一方法。也许你应该重新考虑你的算法,如果不需要的话,不要复制。还可以查看insertYou可以向后迭代向量并删除最后一个元素,因此不必复制。或者,您可以跟踪应该是第一个元素的索引,并从它迭代到最后。有很多方法可以避免复制。创建时保留不保留的内容;它初始化这些值。这是一个持续的过程。如果你想预约,你应该打电话预约。@nicolasbolas我说过这个过程无论如何都会启动的。但是,您认为将调用初始值设定项是正确的。保留,或者,我的意思是,在创建时调整大小,对于std::vector see来说仍然是很难实现的。
std::vector<int> vec1{1, 2, 3, 4, 5};

// Do not call the constructor with the known size here. That would allocate
// AND initialize a lot of data that will be overwritten later anyway.
std::vector<int> vec2;

// Instead, use it on 'reserve' since it only allocates the memory and
// leaves it uninitialized. The vector is still considered empty, but its
// underlying capacity will be big enough to be filled with new data
// without any unnecessary initializations and reallocations occuring (as long
// as you don't exceed the capacity)
vec2.reserve(vec1.size() - 1);

// Nothing expensive should be going on behind the scenes now, just fill it up
for(auto it = vec1.begin(), skip = vec1.begin() + 1 ; it != vec1.end() ; ++it) {
    if(it != skip) {
        vec2.push_back(*it);
    }
}