从std :: vector中删除元素后更新存储的索引

时间:2015-09-25 03:24:29

标签: c++ c++11 stdvector notify erase

假设我有一个点矢量:

vector<int> points;

三角形存储它们构成的点的索引:

struct Triangle {
    int p0, p1, p2;
};

Triangle tri0;
tri0.p0 = 3;
tri0.p1 = 6;
tri0.p2 = 7;

Triangle tri1;
tri1.p0 = 4;
tri1.p1 = 6;
tri1.p2 = 7;

现在我决定删除point[3]。但是,如果我擦除point[3],索引3之后的点索引将向后移动,所以我需要通知所有三角形它们存储的索引可能会被更改。什么可能是通知三角形的合理方式?

1 个答案:

答案 0 :(得分:2)

在我看来,最合理的方式是来删除顶点。因为如果你真的删除它们,那么你必须将所有顶点向右移动(平均 V / 2 元素),然后你必须遍历所有三角形( T 总是检查。

相反,您可以将顶点标记为 dead 。简单地给点数组添加一些不好的值(在你的样本-1中就可以了)。在每个deletition上放置一个标记只需 O(1)。您可能不时想要物理移除死顶点。您可以使用两个完整的过程(一个在顶点上,一个在三角形上),并在线性时间 O(V + T)中压缩网格。

为了方便使用,我建议为你的网格创建一个类。在网格对象中,对类用户透明地保持死区条目的数量。当在删除之后死区的一部分变得相当大(例如超过一半)时,调用死顶点消除。您还可以创建三角形枚举方法,它只会迭代活三角形(仅为方便起见)。

如果在压缩中花费的时间不大于剔除数乘以常数,则此方法确保 O(1)每次剔除的摊销时间。鉴于 T <= c V 在任何时刻(对于某些常量 c ),都是如此。实际上,不太可能看到三角形数量远大于顶点数量的网格,所以你没事。

一个非常不同的解决方案是使用链表而不是数组来存储顶点和三角形(使用指向彼此的指针)。在这种情况下,您可以在 O(Sv)时删除顶点 v ,其中 Sv 是它所属的三角形数。但是这种数据结构的低级性能可能很差。

编辑:我想到了另一个问题。死顶点消除被透明地称为用户,但此时用户可能被捕获在三角形或顶点枚举的中间。显然这种情况会造成很大的麻烦。

为避免危险,请在网格中添加lock / unlock方法。然后,您可以确保只要网格被锁定,其顶点就可以保证按索引方式保持原位。在这种情况下,您可以安全地执行顶点过滤等操作。例如。