我有一个用 C++ 编写的模拟,其中需要维护可变数量的代理,但我无法决定如何很好地实现它。每个代理看起来都类似于:

class Agent{
public:
    Vector2f pos;
    float health;
    float data[DATASIZE];
    vector<Rule> rules;
}

我需要在模拟中维护可变数量的代理,以便:

  1. 优选地,代理的数量没有上限
  2. 我可以轻松添加代理
  3. 在某些情况下我可以轻松删除任何代理(例如健康状况<0)
  4. 我可以轻松地迭代所有代理并执行某些操作(例如健康--)
  5. 最好,我可以使用 openMP 并行化工作,因为许多更新成本较高,但完全独立于其他代理。
  6. (编辑)代理的顺序根本不重要

我应该为代理使用什么样的容器或设计原则?到目前为止,我一直在使用向量,但我认为很难从这个结构中删除:这是我经常需要做的事情,因为事物总是会死去。我应该考虑其他选择吗?我想到了类似List的东西,但我不认为它们可以并行化,因为它们是作为带有迭代器对象的链表实现的?

谢谢

有帮助吗?

解决方案

到目前为止,我一直在使用向量,但我认为很难从这个结构中删除:这是我经常需要做的事情,因为事物总是会死去。

您实际上预计模拟的每一步都会有多少人死亡?对于人类来说似乎“一直”的事情对于计算机来说仍然可能被认为是非常罕见的。例如,如果模拟的每个步骤都会处理数千个代理,但平均每几步只有 1 个代理死亡,那么代理死亡就是一个小事件。对于这些数字,您的程序处理活动代理所花费的时间远多于处理死亡代理的时间,因此担心删除死亡代理的性能可能根本不值得。如果使代理移除更高效最终会导致正常的代理迭代和处理效率降低(但代理移除相对较少),那么这可能是一个糟糕的权衡。

另一方面,如果每个模拟步骤都有大量代理诞生和死亡,那么您可能希望确保可以有效地处理这些事件。所以这实际上取决于您期望处理的数字类型。

我的一般建议是继续使用 std::vector (只要它适合您设计的其余部分),除非您确实预计每个步骤的代理死亡数与代理总数相比会很大。

其他提示

当代理死亡时,您可以将其保留在列表中,以供重新使用。不用担心容器缩小,并且您可以保留矢量的优点。您可以保留一个单独的指向死亡/可重用代理的指针堆栈,只需在代理死亡时推入它,弹出一个指针以回收新代理。

foreach Agent {
    if (agent.health > 0) // skip dead agents
        process rules

列表应该工作得很好。它可以并行化,因为插入或删除元素不会使其他迭代器无效(当然指向被删除元素的迭代器除外)。

如果不需要向后遍历,slist 和 list 一样好,而且速度更快一些。

如果您不关心元素的顺序,请使用 set。

像视频游戏一样使用四叉树。然后搜索 pos 速度很快,移除也很快。(此外,您还可以跨子节点并行化)。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top