摘要描述:
我有一组字符串,称之为“活动集”,以及一组字符串集 - 称之为“可能的集合”。当一个新字符串被添加到活动集时,可能集中的集可能突然成为活动集的子集,因为活动集只缺少该字符串作为其中一个可能的超集。当我向活动集添加新字符串时,我需要一种算法来有效地找到它们。如果相同的数据结构允许我从活动集中删除字符串 (不再是子集)时,相同的数据结构允许我有效地找到奖励点。< / p>
(我在上面摘要中根据字符串的集合和子集来描述下面描述的问题的原因是我在(Io)中编写的语言是动态类型的。对象确实有一个“类型”字段但是它是一个包含对象类型名称的字符串。) 背景: 在我的游戏引擎中,我有 GameObjects ,它可以添加几种类型的 Representation 对象。例如,如果GameObject具有物理存在,则可能会向其添加PhysicsRepresentation(或者如果它不是实体对象则不会)。它可能会添加各种GraphicsRepresentations,例如网格或粒子效果(如果你有多个视觉效果附加到同一个游戏对象,你可以拥有多个)。 这一点是分离子系统,但你无法完全分离所有内容:例如,当GameObject同时具有PhysicsRepresentation和GraphicsRepresentation时,需要创建第3个对象,将GraphicsRepresentation的位置连接到PhysicsRepresentation的位置。为了达到这个目的,同时仍然将所有组件分开,我有 Interaction 对象。 Interaction对象封装了有关两个系统组件如何交互的交叉知识。 但是为了保护GameObject不必过多地了解表示和交互,GameObject只提供了一个通用的注册表,其中,当GameObject中存在Representations的特定组合时,可以注册交互原型对象。当一个新的Representation被添加到GameObject时,GameObject应该查看它的注册表并激活那些新的Representation的存在以及现有的Representations新启用的Interaction对象。 我只是坚持应该为这个注册表使用什么数据结构以及如何搜索它。 勘误表: 字符串集不一定要排序,但我可以选择将它们存储为已排序。 虽然互动最常见于两个表述之间,但我不想将其限制在此之间;我应该能够通过3个或更多不同的表示来触发交互,甚至可以基于仅1个表示触发的交互。 我想优化它,以便尽可能快地添加/删除表示。 我将有许多活动集(每个游戏对象都有一个活动集),但我只有一个可能的集(所有已注册的交互类型的集合)。所以我不关心构建表示可能集合的数据结构需要多长时间,因为只要比较不同的活动集的算法对可能的集合数据结构没有破坏性,它只需要完成一次。
答案 0 :(得分:3)
如果你的集很小,最好的表示是使用位集。首先,构建一个从字符串到连续整数0..N的映射,其中N是不同字符串的数量。然后通过将1<<k
按位OR运算到数字中来构建集合。这使您可以将设置操作转换为按位操作,这些操作非常快(交集是&
;联合是|
,依此类推。)
以下是一个示例:假设您有两套,A={quick, brown, fox}
和B={brown, lazy, dog}
。首先,构建一个字符串到数字的映射,如下所示:
quick - 0
brown - 1
fox - 2
lazy - 3
dog - 4
然后您的设置将变为A=00111b
和B=11010b
。他们的交集是A&B = 00010b
,他们的联合是A|B = 11111b
。您知道,如果X
,则Y
集是X == X&Y
集的子集。
答案 1 :(得分:2)
这样做的一种方法是为每个子集保留一个字符串不在主集中的计数,以及从字符串到包含该字符串的子集列表的映射,以便您可以更新向活动集添加或删除新字符串时的计数,并注意计数何时降至零。
当一个事实变为真时,这个问题让我想起基于规则的系统中的触发规则,这对应于添加到活动集的新字符串。其中许多系统使用http://en.wikipedia.org/wiki/Rete_algorithm。 http://www.jboss.org/drools/drools-expert.html是一个基于规则的开源系统 - 虽然看起来现在有很多企业系统包围它。