如何从另一个向量/对象集构造新的向量/指针集

How to construct a new vector/set of pointer from another vector/set of object?

本文关键字:向量 指针 对象 另一个      更新时间:2023-10-16

背景

我想操作向量的副本,但对其每个元素进行向量复制操作通常是昂贵的操作。

有一个概念叫做浅拷贝,我在某个地方读到它是默认的拷贝构造函数行为。然而,我不确定为什么它不起作用,或者至少我试着复制矢量对象,结果看起来像是一个深度复制。

struct Vertex{
    int label;
    Vertex(int label):label(label){ }
};
int main(){
    vector<Vertex> vertices { Vertex(0), Vertex(1) };
    // I Couldn't force this to be vector<Vertex*>      
    vector<Vertex> myvertices(vertices); 
    myvertices[1].label = 123;
    std::cout << vertices[1].label << endl; 
    // OUTPUT: 1 (meaning object is deeply copied)
    return 0;
}

Naive解决方案:用于指针复制

int main(){
    vector<Vertex> vertices { Vertex(0), Vertex(1) };
    vector<Vertex*> myvertices;
    for (auto it = vertices.begin(); it != vertices.end(); ++it){
        myvertices.push_back(&*it);
    }
    myvertices[1].label = 123;
    std::cout << vertices[1].label << endl;
    // OUTPUT: 123 (meaning object is not copied, just the pointer)
    return 0;
}

改进

是否有其他更好的方法或std::vector API来构造仅包含原始向量中每个元素的指针的新向量?

您可以将元素向量转换为指向原始向量元素的指针向量的一种方法,与您的示例相比,这种方法在效率方面更好,因为它预先分配了指针向量的缓冲区,IMHO更优雅,方法是使用std::transform,如下所示:

std::vector<Vertex*> myvertices(vertices.size());
std::transform(vertices.begin(), vertices.end(), myvertices.begin(), [](Vertex &v) { return &v; });

实时演示

或者,如果您不想为一元运算符使用lambda:

std::vector<Vertex*> myvertices(vertices.size());
std::transform(vertices.begin(), vertices.end(), myvertices.begin(), std::addressof<Vertex>);

实时演示

注意:如果更改原始矢量,则会使指针矢量中的指针无效。

感谢@kfsone在主要问题上注意到,很少有人想在不利用其核心思想的情况下跟踪来自另一个对象向量的指针。他提供了一种通过使用位掩码来解决类似问题的替代方法。在他提到这一点之前,我一开始可能并不清楚。

当我们试图只存储另一个向量的指针时,我们很可能想对另一个对象进行一些跟踪、内务管理(保持跟踪(。稍后在指针本身上执行,而不接触原始数据。对于我的例子,我正在通过brueforce方法解决一个最小顶点覆盖问题。其中,我将需要生成顶点的所有排列(例如,20个顶点将生成2**20=100万++排列(,然后我通过缓慢迭代顶点覆盖中的每个顶点来修剪所有不相关的排列,并删除顶点覆盖的边。在这样做的时候,我的第一直觉是复制所有指针以确保效率,然后我可以一个接一个地删除指针。

然而,研究这个问题的另一种方法是根本不使用向量/集,而是将每个指针作为位模式进行跟踪。我不想详述,但可以向别人学习。

性能差异非常显著,因此按位计算,您可以在没有太多问题的情况下实现O(1(恒定时间,而使用特定容器,您往往必须迭代将算法绑定到O(n(的每个元素。最糟糕的是,如果你正在处理NP难题,你需要保持常数因子尽可能低,在这种情况下,从O(1(到O(N(是一个巨大的差异。