【问题标题】:Data structure for fast random access and sequential access in R^3 (x,y,z)R^3 (x,y,z) 中用于快速随机访问和顺序访问的数据结构
【发布时间】:2016-02-17 08:53:32
【问题描述】:

我想找到一个内存高效的数据结构,用于搜索一个巨大的 R^3 坐标网络,可能有 100,000-500,000 个坐标。我看过看起来不错的 k-d 树,那里有什么好的数据结构可以进行快速随机和顺序访问吗?编程语言将是 C++ 或 C。我研究了 k-d-tree 和 R^*-tree 是否有一些更有效的数据结构?

id x y z

1 0.1 0.05 0.3

2 0.3 0.22 2.3

3 0.1 0.2 3.3

等等

【问题讨论】:

  • 您需要从结构中获得什么样的查询?对于快速顺序和随机访问std::vector 就足够了。
  • 我想用给定的 (x,y,z) 坐标进行搜索,它应该是内存高效的。我不认为 std::vector<:vector> > >;对于顺序和随机访问来说会那么有效。
  • @Marcus 我的意思是std::vector&lt;point_3d&gt;。这是顺序和随机访问的最佳方式。如果你想搜索一个点,这只是另一个问题。由于您实际上并没有使用数据的几何性质,因此简单的 std::mapstd::unordered_map 就可以了。
  • 当您说“使用 (x,y,z) 搜索”时,您的意思是完全匹配还是近似匹配。后者要困难得多。请澄清你想对数据结构做什么。 “随机访问”不清楚。
  • 考虑使用您的显卡来解决您的问题。着色器可以并行处理 3D 数据点。

标签: c++ data-structures tree


【解决方案1】:

假设您需要在任意矩形棱镜内进行搜索,您应该考虑使用八叉树。 Wiki 上有一篇文章,https://en.wikipedia.org/wiki/Octree

【讨论】:

  • 感谢您的回答!如果我想在八叉树中存储小数点并使用给定的坐标进行搜索,这可能吗?
【解决方案2】:

这是如何通过所有这些点最快和记忆最有效地找到点的存在或用它组织地图的方法。 您需要为您的 3d 坐标类实现特殊的比较对象 http://ru.cppreference.com/w/cpp/utility/functional/less。将其用作 std::map 或 std::vector 访问要求的模板参数。

template< class T >
struct My3DLess;
bool operator()(const T &lhs, const T &rhs) const
{
    return lhs.x < rhs.x && lhs.y < rhs.y && lhs.z < rhs.z;
}

typedef std::map<My3DPoint,MyMappedObject,My3DLess> My3DMap;

如果您的插入不像 fetch 那样频繁,则需要使用向量。你可以使用这个排序插入函数:

typedef< typename T, typename Pred >
typename std::vector<T>::iterator
    insert_sorted( std::vector<T> & vec, T const& item, Pred pred )
{
    return vec.insert ( std::upper_bound( vec.begin(), vec.end(), item, pred ), item );
}

typedef std::vector<My3DPoint> My3DVector;
My3DVector my3DVector;

// inserting
insert_sorted( my3DVector, my3DPoint, My3DLess() );

// check existance
if ( std::binary_search( my3DVector.begin(), my3DVector.end(), my3DPoint, My3DLess() ) )
    { ... }

【讨论】:

  • 这有什么帮助?
  • 您需要从结构中获得什么样的查询? @lisyarus 问过你吗?我已经展示了如何以最快的速度和记忆有效地通过所有这些点找到存在的点或用它组织地图。
  • 我需要的查询是使用给定的 (x,y,z) 坐标进行搜索,并且可能通过给定的 id 进行搜索。应该可以使用顺序和随机访问进行搜索。由于它有大量的坐标,因此具有良好的内存效率很重要
  • 最有效的内存方法是使用数组,正如我所展示的。但是必须对插入其中的内容进行排序。排序需要过多的 CPU 资源。点阵频繁更新是不好的。你需要选择最适合你的。地图(更多内存,快速插入)或矢量(更快速搜索)。
【解决方案3】:

如果内存效率至关重要,我会推荐PH-Tree(我自己的实现)之类的东西。根据数据量和维度,它比包含相同坐标(例如 10M 点和 >7 维)的普通 float[]float[][] 需要更少的空间。对于 3 维,它需要更多空间,但仍比大多数其他数据结构要少。

它是四叉树/八叉树与 trie(前缀共享)和一些其他算法的混合,使其适合大数据和高维度。

附加好处:支持非常快速的随机更新,它们几乎不会比查找时间长。查询速度与 R-Trees 等类似。

主要缺点:目前没有 C/C++ 版本,只有 Java 版本。此外,代码非常复杂,需要一些工作才能翻译。另一个缺点是,对于小于 1,000,000 点的小数据集,PH-Tree 有时会有点慢;它可能会变得更快(!)有更多的点。

编辑 顺序访问返回稳定的顺序。作为额外的奖励,顺序访问和窗口查询返回 z 排序结果。但是,不能按 ID 订购。

【讨论】:

  • 是不是类似于多维特里树?如果是,我相信查找复杂度是 O(key length),对于树来说它可能大于 O(log N)。我已经看到尝试比树执行得更差......如果你可以键入浮点数,你有一个基于哈希表的解决方案吗?
  • 我认为大多数多维度尝试(k 维度)只是将位交错并将它们存储在二叉树中,即 O(64*k),这当然很慢。 PH-Tree 的性能要好得多,因为对于大多数内部操作,它可以摆脱 k 并且在 O(64*k) 中也远低于 '64',假设 k
  • 说实话,每次插入 1us 听起来并不是很快。但我不习惯 100M 条目的容器。哈希表可以做得更好 2 个数量级(使用一个小条目)。这是一个有趣的问题。我认为基于哈希表的解决方案会快得多,但存在键控浮点问题,并且会使用更多内存
  • 快 2 个数量级是很多,即每次插入大约 60 个周期...。对于纯插入/查找(这是所要求的),哈希图确实更快,但不能进行几何查询。它们也比 PH-Tree 消耗更多的空间(这是 OP 的要求)。在上面的链接中有一个名为 PhTreeRevisited 的 PDF,在图 6 中它显示树几乎不受条目数量的影响,尤其是对于集群数据集。对于小数据集,如果不需要kNN&window查询,内存是次要的,我是不会用的,否则我觉得值得一看。
  • 感谢您的回答。我正在研究 3d 空间并希望将坐标映射到特定 id 是否可以在 PH-tree 中执行此操作?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-11-16
  • 1970-01-01
  • 1970-01-01
  • 2010-10-27
  • 1970-01-01
  • 2016-06-06
  • 1970-01-01
相关资源
最近更新 更多