C++ 从std::vector中删除多个对象?

C++ 从std::vector中删除多个对象?,c++,vector,C++,Vector,这是我的问题,假设我有一个包含int的std::vector 假设它有50,90,40,90,80,60,80 我知道我需要删除第二、第五和第三个元素。我不一定总是知道要删除的元素的顺序,也不知道要删除多少。问题是通过删除一个元素,这会更改其他元素的索引。因此,我如何删除这些内容并补偿索引的更改。(排序然后使用偏移量线性擦除不是选项) 谢谢我提供了几种方法: 1。不保留元素原始顺序的快速方法: 将向量的当前最后一个元素指定给要擦除的元素,然后擦除最后一个元素。这将避免大幅波动,除最后一个指数外,

这是我的问题,假设我有一个包含int的std::vector

假设它有50,90,40,90,80,60,80


我知道我需要删除第二、第五和第三个元素。我不一定总是知道要删除的元素的顺序,也不知道要删除多少。问题是通过删除一个元素,这会更改其他元素的索引。因此,我如何删除这些内容并补偿索引的更改。(排序然后使用偏移量线性擦除不是选项)


谢谢

我提供了几种方法:

1。不保留元素原始顺序的快速方法:

将向量的当前最后一个元素指定给要擦除的元素,然后擦除最后一个元素。这将避免大幅波动,除最后一个指数外,所有指数都将保持不变。如果从后面开始擦除,则所有预计算的索引都将是正确的

void quickDelete( int idx )
{
  vec[idx] = vec.back();
  vec.pop_back();
}
我看这本质上是Klaim指出的erase-remove成语的手工编码版本

2。保留元素原始顺序的较慢方法:

步骤1:标记所有要删除的矢量元素,即使用特殊值。这有O个(|要删除的索引|)

步骤2:使用
v.Erase(删除(v.begin()、v.end()、特殊值)、v.end())擦除所有标记的元素。这有O(|向量v |)

因此,假设索引列表比向量短,则总运行时间为O(| vector v |)

3。另一种保留元素原始顺序的较慢方法:

如中所述,使用谓词并删除if。使之高效,并尊重
不是“排序然后用偏移量线性擦除”,我的想法是使用哈希表实现谓词,并在删除过程中调整存储在哈希表中的索引,然后返回true,正如Klaim所建议的那样。

使用谓词和算法删除\u,如果你能实现你想要的:参见

不要忘记删除该项目(请参阅)

谓词将只保留每个值的idx,以便在每次返回true时删除并减少它保留的所有索引


也就是说,如果你能用remove-erase习惯用法删除每个对象,那就让你的生活变得简单吧。

我会将你不想删除的元素移动到一个临时向量,然后用这个向量替换原始向量。

向后删除这些项目。换句话说,先擦除最高的索引,然后再擦除下一个最高的索引等。您不会使任何以前的迭代器或索引无效,因此您可以使用多个擦除调用的明显方法。

这是否可行:

void DeleteAll(vector<int>& data, const vector<int>& deleteIndices)
{
    vector<bool> markedElements(data.size(), false);
    vector<int> tempBuffer;
    tempBuffer.reserve(data.size()-deleteIndices.size());

    for (vector<int>::const_iterator itDel = deleteIndices.begin(); itDel != deleteIndices.end(); itDel++)
        markedElements[*itDel] = true;

    for (size_t i=0; i<data.size(); i++)
    {
        if (!markedElements[i])
            tempBuffer.push_back(data[i]);
    }
    data = tempBuffer;
}
void DeleteAll(向量和数据、常量向量和删除索引)
{
向量标记元素(data.size(),false);
向量缓冲区;
reserve(data.size()-deleteIndexes.size());
对于(vector::const_迭代器itDel=deleteIndexes.begin();itDel!=deleteIndexes.end();itDel++)
markedElements[*itDel]=true;

对于(size_t i=0;i如果其余元素的顺序无关紧要,则可以使用此方法

#include <iostream> 
#include <vector>

using namespace std;
int main()
{
    vector< int> vec;
    vec.push_back(1);
    vec.push_back(-6);
    vec.push_back(3);
    vec.push_back(4);
    vec.push_back(7);
    vec.push_back(9);
    vec.push_back(14);
    vec.push_back(25);
    cout << "The elements befor " << endl;
    for(int i = 0; i < vec.size(); i++) cout << vec[i] <<endl;
    vector< bool> toDeleted;
    int YesOrNo = 0;
    for(int i = 0; i<vec.size(); i++)
    {
        
        cout<<"You need to delete this element? "<<vec[i]<<", if yes enter 1 else enter 0"<<endl;
        cin>>YesOrNo;
        if(YesOrNo)
            toDeleted.push_back(true);
        else
            toDeleted.push_back(false);
    }
    //Deleting, beginning from the last element to the first one
    for(int i = toDeleted.size()-1; i>=0; i--)
    {
        if(toDeleted[i])
        {
            vec[i] = vec.back();
            vec.pop_back();
        }
    }
    cout << "The elements after" << endl;
    for(int i = 0; i < vec.size(); i++) cout << vec[i] <<endl;
    return 0;
}
#包括
#包括
使用名称空间std;
int main()
{
向量vec;
向量推回(1);
向量推回(-6);
向量推回(3);
向量推回(4);
向量推回(7);
向量推回(9);
向量推回(14);
向量推回(25);
coutWhile by Peter G.在变体一(交换和弹出技术)中,当您不需要维护订单时,速度最快,下面是未提及的维护订单的替代方案

使用C++17和C++20,可以使用标准算法从向量中删除多个元素。由于
std::stable_partition
,运行时间为O(N*Log(N))。没有外部辅助数组,没有过度复制,所有操作都在原地完成。代码是“一行”:

然后将此检查器lambda馈送到
std::stable_partition
算法,该算法保证对原始(未赋值!)数组
v
中的每个元素只调用此lambda一次

auto end_of_selected = std::stable_partition(
                           v.begin(),
                           v.end(),
                           filter);
所选迭代器的
end\u指向应该保留在输出数组中的最后一个元素之后,因此我们现在可以向下调整
v
的大小。为了计算元素的数量,我们使用
std::distance
从两个迭代器中获得
size\u t

v.resize(std::distance(v.begin(), end_of_selected));
这与顶部的代码不同(它使用
itemIndex
跟踪数组元素)。为了去掉
itemIndex
,我们捕获对源数组
v
的引用,并使用指针算法在内部计算
itemIndex

多年来(在这个和其他类似的站点上)已经提出了多种解决方案,但通常它们使用多个带条件的“原始循环”和一些擦除/插入/回推调用。
稳定分区
背后的思想在Sean Parent的这篇文章中得到了很好的解释

这提供了一个类似的解决方案(如果使用的是
std::binary_search
,而不是
std::binary_search
,则不假定对
selection
进行排序-
std::find_),但它还使用了一个helper(递增)变量,该变量禁用了在较大数组上并行处理的可能性


从C++17开始,
std::stable_partition
有一个新的第一个参数(
ExecutionPolicy
)这允许算法的自动并行化,进一步减少大型阵列的运行时间。为了让自己相信这种并行化确实有效,Hartmut Kaiser的另一篇文章解释了其内部内容。

这并不繁琐,因为当您从向量中删除元素时,索引会发生变化

[0] hi
[1] you
[2] foo

>> delete [1]
[0] hi
[1] foo
如果保留删除元素的次数计数器,并且如果有要按排序顺序删除的索引列表,则:

int counter = 0;
for (int k : IndexesToDelete) {
  events.erase(events.begin()+ k + counter);
  counter -= 1;
}

然后与自身交换是不可行的,而且
pop\u back
仍然做正确的事情
[0] hi
[1] you
[2] foo

>> delete [1]
[0] hi
[1] foo
int counter = 0;
for (int k : IndexesToDelete) {
  events.erase(events.begin()+ k + counter);
  counter -= 1;
}