对于没有太多信息的标题感到抱歉,我无法想到更好的事情。当我说效率时,我的意思是代码不是cpu密集的。
问题: 想象一下用块制成的3D宇宙飞船,就像在我的世界中建造一样。我想将这个形状中的每个块的位置存储在一个自制的Ship类中。
为此,我在Ship类中使用了private List<ShipBlock> shipBlocks;
。这里的ShipBlock是一个自制的类,它以向量Vec3(int x, int y, int z)
的形式保存一个位置,以及与此问题无关的一些其他信息。
但现在我想在船上进行测试。船在某个testPosition(x,y,z)上包含ShipBlock,如果是,则为此返回ShipBlock。然而,我没有找到有效地做到这一点的方法。循环整个列表并测试每个位置对抗测试位置是相当昂贵的,我希望它能够快速。
相反,我决定制作一个Map<Vec3, ShipBlock> shipBlocksMap
来存储信息。钥匙将是ShipBlock的位置。我可以简单地做shipBlocksMap.get(testPosition)
,如果船在该位置有一个ShipBlock,它将返回正确的ShipBlock。如果不是,它将返回null。
这似乎正是我想要的,直到我移动船并且所有ShipBlock都有新的位置。我在这里了解到,如果您作为关键字提供的对象发生变化,地图中的关键字就不会改变。因此,如果我现在使用shipBlocksMap.get(testPosition)
使用移动船舶中的位置,它将返回null,因为关键字仍然是旧位置。 (对不起,如果它令人困惑,我不确定如何更好地解释它)
问题: 我在这里问的问题是:假如这艘船可以包含数以万计的ShipBlocks,那么测试它是否包含具有特定位置的ShipBlock的最有效方法是什么。我应该以什么方式存储船舶的船闸,以便有效地进行检查?
代码: 任何人都希望在这里看到它是Ship和ShipBlock类的代码。
public class ShipBlock
{
public Vec3 position;
public String shipBlockType;
public ShipBlock(Vec3 position, String shipBlockType)
{
this.position= position;
this.shipBlockType = shipBlockType;
}
}
public class Ship
{
private Map<Vec3, ShipBlock> shipBlocksMap;
public Ship(Map<Vec3, ShipBlock> shipBlocksMap)
{
this.shipBlocksMap = shipBlocksMap;
}
public ShipBlock containsShipBlock(Vec3 position)
{
return shipBlocksMap.get(position);
}
}
答案 0 :(得分:4)
我认为最重要的设计变化是将块的位置相对保存到船的位置。
这样,您不需要在船舶移动时更改块的键,并且可以轻松地使用Map<Vec3, ShipBlock> shipBlocksMap
进行恒定时间测试,其中键是相对位置。
您可以通过计算(概念上)relative_block_pos = absolute_block_pos - ship_pos
获得相对位置。
这意味着您需要存储船舶的位置。
作为一种选择,您可以简单地选择船舶的第一个区块作为船舶的位置,因此第一个区块始终具有坐标(0, 0, 0)
。
这样,将所有块的坐标更改为最小值(但在大多数情况下应该不需要)。
答案 1 :(得分:0)
空间分区树可能是您的最佳选择;见space-partitioning trees。您的模型世界的一半可能是空的,并且在许多这些结构中,单个测试将揭示这一点,并且可能有助于未来的测试,直到宇宙的一半以某种方式发生变化。你有责任保持结构,但听起来结构的变化超过了测试。另一种方法可能是使用元球或Voronoi船体围绕块或块集群,以便您可以将每个测试量减少到单个测试中。