在动态,可变大小的2D数据结构中存储3D索引坐标数据对的最有效方法?

时间:2018-09-19 02:43:52

标签: c# arrays list unity3d data-structures

这是一个有趣的数据结构难题,对于我正在编写C#的情况,也许所有人都可以帮助我。

上下文/约束:

我正在使用一个库(特别是新的Unity ECS预览包),该库允许我以非常紧凑/高效/本机的方式存储数据,以实现无垃圾收集的快速访问和操作。一段时间以来,它支持在FixedArray s中存储数据:

ComponentType.FixedArray<T>(int fixedCapacity) //pseudo-code

出于性能和安全原因,API不允许将任何类型的托管数据存储在这些数组中,这意味着它们必须全部是线性的(无嵌套数组或多维),并且数据元素本身必须极其简单(原始或直接可序列化的结构,没有精美的LinkedList或对其他数据结构的引用)。 我不能使用HashTableDictionary或任何其他类似的数据高级数据结构来解决此问题,我必须使用提供的数据结构!

问题:

我正在尝试在具有相关3D点整数坐标的数组中存储基本的“实体”对象。我想使用此坐标来访问结构,并从所述坐标检索/修改/删除我的对象。因此,这是一个简单的问题,即使用哈希函数可以使用3D坐标访问线性索引的固定宽度数组。

//Pseudo-Code, this is not the actual code itself.
//In actuality the Fixed Arrays are associated with Entities in an ECS system.

var myStructure = new ComponentType.FixedArray<Entity>(512);//define array
struct DataPair {
  Entity entity;//the element we're storing
  Vector3 threeDIntegerCoordinate;//from 1x1x1 to 8x8x8
}

//...
int lookupFunction(Vector3 coordinate) {...} //converts 3D coord to 2D linear index

DataPair exampleDataPair = new DataPair(...);
//Data WAS stored like this:
myStructure[lookupFunction(exampleDataPair.threeDIntegerCoordinate)] = exampleDataPair.entity;
//Extremely fast access/lookup time due to using coordinate as index value.

基本上,我生成了一个可变量的实体(1到512,一个8x8x8立方体),并使用转换函数将索引按线性索引值与每个3D点坐标相关联,将它们按索引存储到FixedArray中。在固定数组中查找坐标值非常快,就像访问索引一样简单。

但是

该软件包已更新,他们用新的FixedArray数据结构替换了DynamicBuffer,该数据结构现在是可变宽度的。相同的约束条件适用于可以存储哪些数据,但是现在,如果实体的多维数据集稀疏(不完全满),则无需为该结构中不存在的实体引用保留空间。考虑到大多数实体的多维数据集尚未完全满,这将大大减少我的内存使用量,而且我一次要在内存中存储数百万个这样的缓冲区。缓冲区元素由整数索引。可以一次使用多个DynamicBuffer(这意味着我们可以根据需要将坐标与元素一起存储在两个并行缓冲区中)。

//New data structure provided. Variable-width! Also indexed linearly.
var myStructure = new ComponentType.DynamicBuffer<Entity>();
//Is very similar to C# List or ArrayList in Java, for example, contains functions:
myStructure.Add(T element);
myStructure.AddRange(...);
myStructure.Length();
myStructure.resizeUninitialized(int capacity);
myStructure.Clear();

本质上, 是在保持3D坐标的同时将这些可变数量的元素存储在动态无量纲数据结构(类似于List)中最有效的方法是什么基于索引的索引,而无需使用复杂的嵌套数据结构呢?我的系统受查找/访问时间的影响比受内存空间的影响更大。

可能的解决方案:

天真的解决方案只是模拟DynamicBuffer,使所有FixedArray的长度等于我要存储的元素的最大数量(512实体卷)。这将需要对我的代码库进行最小的更改,并允许我使用当前的翻译功能按坐标访问它们,但不会利用动态数据结构的节省空间的功能。看起来像这样:

//Naive Solution:
myStructure.resizeUninitialized(512); //resize buffer to 512 elements
//DynamicBuffer is now indexed identically to FixedArray
Entity elementToRetrieve = myStructure[exampleDataPair.threeDIntegerCoordinate];

我计划的解决方案是使用两个 parallel DynamicBuffer:一个包含所有实体,另一个包含所有3D点。然后,当我想按坐标查找实体时,我在坐标缓冲区中查找3D点,并使用该元素的索引在主缓冲区中找到合适的实体。

//Possible better solution:
myStructure1 = new ComponentType.DynamicBuffer<Entity>();
myStructure2 = new ComponentType.DynamicBuffer<Vector3>();
//to access an element:
Entity elementToRetrieve = myStructure1[myStructure2.Find(exampleDataPair.threeDIntegerCoordinate)];
//I would have to create this theoretical Find function.

此解决方案的缺点:

  • 需要搜索,这意味着可能还需要排序。
  • 每次对结构进行重大修改时都需要进行排序,这将增加大量的计算开销。
  • 需要在已经非常复杂的数据结构(不设计为要进行搜索/排序(它可能不会线性地存储在内存中))之上编写我自己的搜索/排序算法。
  • 参考地点?保留处理器缓存/推测性执行以实现高性能非常重要。

如何在幼稚的解决方案和涉及搜索/排序的复杂解决方案之间找到快乐的中介?有没有理论上的数据结构或算法可以解决我完全缺失的这个问题?基本上,我需要像地图一样有效地使用列表。

很抱歉,如果这是一个很长的问题,但是我想纠正这个问题,这是我在StackExchange上的第一个帖子。请温柔!感谢您的所有帮助!

0 个答案:

没有答案