我有一个数据数组(通用顶点数据)。我需要能够根据位置搜索数组的元素。目前,每个顶点元素都记录自己的位置,我只需使用for-loop
搜索每个元素并比较位置。我必须在我的程序中做很多事情并且它对性能至关重要。循环遍历每一个元素似乎真的非常低效。
我使用C ++,顺便说一句。
我的问题是:有更好的方法吗?也就是说,有没有一种方法可以直接根据3D位置访问必要的元素?这些职位是整数,所以这可能有所帮助。
我想过简单地使用3D数组(即顶点[256] [256] [256]),但我无法承受浪费的内存,因为只有大约30-50%的顶点位置实际上包含一个顶点。也许这可以通过指针来实现?未分配时是否使用内存?
3D阵列的另一个问题是顶点可以分布在几乎无限的区域,这将形成一个非常非常大的阵列。此外,顶点有效地动态添加,这意味着它们可以添加到< 0位置,这意味着数组必须向后移动并重新分配每个元素。
如果有人有任何建议,我将非常感激:)
答案 0 :(得分:2)
您可能考虑的解决方案是使用稀疏网格作为您的ADT。
std::unordered_map
是一个散列映射,可用于创建稀疏网格数据结构。如果你为3d向量写一个好的哈希,你可以获得很好的O(1)读取性能,这将接近原始数组的性能。
散列映射也允许您使用“几乎无限”的区域(当然约束将在底层数据类型中。
抱歉延误。
对于unordered_map,这是一个很好的信息资源:unordered_map hash function c++
我使用一对int在我自己的项目中实现,但我确信它可以用于三维坐标。
namespace std {
template <class T>
inline void hash_combine(std::size_t & seed, const T & v) {
std::hash<T> hasher;
seed ^= hasher(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
}
template<> struct hash<pair<int, int> > {size_t operator()(pair<int, int> x) const { size_t seed=0; hash_combine(seed, x.first); hash_combine(seed, x.second); return(seed); } };
}
然后你可以声明你的unordered_map
std::unordered_map<std::pair<int, int>, [VALUE] > my_map; //[VALUE] being the data type of vertex
在此之后,您可以将结构视为常规std::map
。如果你不确定如何使用它,那里有很多例子。
对于3d坐标,您可以声明自己的结构
struct vector
{
int i,j,k;
};
然后修改散列函数(为便于阅读而格式化)
template<> struct hash<vector > {
size_t operator()(vector x) const {
size_t seed=0;
hash_combine(seed, x.i);
hash_combine(seed, x.j);
hash_combine(seed, x.k);
return(seed);
}
};
答案 1 :(得分:2)
Octree可能是基于体素的地形(或模型)的最佳解决方案。八叉树的基本概念由节点和叶子组成。每个节点(和叶子)表示立方体空间,每个节点包含8个子节点(或叶子),使得每个子节点占用其父节点的1/8空间(参见picture)。
叶子与节点的不同之处在于没有更多的子节点但是包含数据本身 - 在你的情况下是顶点数组。
八叉树的深度取决于你,它实际上取决于地形的细节程度。现在,如果要将顶点组织到树中,对于每个顶点,您将首先将其发送到主节点(树的根节点,即包含所有其他节点),然后将确定顶点所属的子节点基于一个职位。然后递归传递顶点,直到它到达叶节点,并将其存储在数组中。
对于简单,这是带有四叉树的2D示例:
(4,4)
-----------------
| 3 | 4 |
| | |
-----------------
| 1 | 2 |
| | |
-----------------
(0,0)
让我们说地形的大小是4x4。在此示例中,我们仅使用主节点作为包含叶节点的节点。如果我们现在有顶点,可以说(0.2, 3.2)
。顶点传递给根节点。从0.2 < 4/2
和3.2 > 4/2
开始,节点将顶点发送给叶子号。 3存储它的地方。如果您在空间(或本例中的平面)中搜索位置,则可以采用与存储描述类似的方式进行操作。
在您的实现中,您可以使用指针表示节点的子节点/叶子。如果要优化空间,则根本不必存储每个节点的尺寸和位置,而是假设每个节点的尺寸为1x1x1
,然后在传递之前相应地变换每个顶点。
即您的地形大小为1000x1000x1000
,顶点位于(600,600,100)
。现在,您将位置除以大小,以便获得传递给节点的位置(0.6,0.6,0.1)
。由于0.6 > 1/2
和0.1 < 1/2
您将相应地传递给节点,但在您将其转换之前,它再次从高分量中减去1/2,然后将所有分量乘以2(作为子节点)得到的位置(0.2, 0.2, 0.2)
将在所有维度上缩小两倍......等等。然而,这一点更高级,因为每次使用树时都需要依赖它。
很难在互联网上找到有关该主题的教程,但有许多实现需要学习。 以下是我发现的情侣:
http://www.flipcode.com/archives/Octree_Implementation.shtml https://github.com/brandonpelfrey/SimpleOctree
一个实际的教程(但它很重): http://www.xbdev.net/maths_of_3d/octree/tutorial/