【问题标题】:How to construct a new vector/set of pointer from another vector/set of object?如何从另一个向量/对象集构造一个新的向量/指针集?
【发布时间】:2016-08-22 20:51:28
【问题描述】:

背景

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

我在某处读到的称为浅拷贝的概念是默认的拷贝构造函数行为。但是我不确定为什么它不起作用,或者至少我尝试复制向量对象,结果看起来像一个深拷贝。

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;
}

天真的解决方案:用于指针复制。

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 来构造一个新向量,其中只包含原始向量中每个元素的指针

【问题讨论】:

  • 如果您使用myvertices,您将不会操作原始矢量的副本,您将更改原始矢量,您确定这是您想要的吗?
  • 你为什么不直接通过vertices来操作元素呢?我不明白你的问题。
  • 因为我正在执行一种算法,需要我一个一个地删除顶点,并且应该为另一个测试用例再次重置它。
  • 如果您不想更改原始的std::vector,那么您只需要像您的第一个代码 sn-p 所示那样进行深层复制。
  • 我不想拥有深拷贝。我想确保操作非常高效,就像将所有元素的指针复制到另一个向量中一样。

标签: c++ c++11 pointers vector set


【解决方案1】:

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

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

Live Demo

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

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

Live Demo

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

【讨论】:

  • 是的,我想从新创建的myvertices 中删除,以便记账。
  • @ArchbishopOfBanterbury 是的,它提供了一种更好的方法来创建指针向量。我认为这就是 OP 所要求的Is there any other better approach or std::vector API to construct a new vector containing just the pointer of each of the elements in the original vector?
  • 使用 Boost 迭代器适配器,您可以将其稍微改写为 auto vertexPtrs = vertices | boost::adaptors::transformed([](Vertex&amp; v) { return &amp;v; }); std::vector&lt;Vertex*&gt; myvertices(vertexPtrs.begin(), vertexPtrs.end());
  • @PaulMcKenzie 是的,vertices 内部的原始 Vertex 对象已修复。我设计数据结构的方式使得 Vertex 只定义在一个地方,并且这个顶点不可修改,不可添加,不可删除。只能添加或删除指针,并且必须发生在不同的集合或不同的向量中。
  • @Yeo -- 你指的是vector&lt;Vertex&gt;吗?这就是我所指的。如果该向量改变大小(即您添加更多点),那么您之前存储在vector&lt;Vertex*&gt; 中的那些指针将失效。
【解决方案2】:

感谢@kfsone 注意到主要问题,即很少有人想要跟踪来自另一个对象向量的指针而不利用其背后的核心思想。他提供了一种替代方法,通过使用位掩码来解决类似问题。起初对我来说可能并不明显,直到他提到这一点。

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

然而,研究这个问题的另一种方法是根本不使用向量/集合,而是将这些指针中的每一个作为位模式进行跟踪。我不会详细介绍,但请随时learn from others

性能差异非常显着,因此按位计算,您可以毫无问题地实现 O(1) 恒定时间,而使用特定容器时,您往往必须迭代将算法绑定到 O( n)。更糟糕的是,如果你是暴力破解 NP 难题,你需要保持常数因子尽可能低,在这种情况下从 O(1) 到 O(N) 是一个巨大的差异。

【讨论】:

  • 我刚刚注意到这个方法的另一个问题。该方法并不总是适用于大数据。上面的答案很小(只有 20 个顶点或 20 位)。当遇到大量数据时,您仍然需要跟踪它的指针。想象一下,在 20 位以下,您可以执行左移 20 位,如果给出的问题高于 10000 会怎样。您不可能执行左移 10000。这远远超出了int 数据类型的大小。因此,您仍然需要一个容器并对大型数据集执行 O(N) 操作。
猜你喜欢
  • 2018-09-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-03-30
  • 1970-01-01
  • 2017-11-28
  • 2016-05-15
相关资源
最近更新 更多