【问题标题】:Data structure for fast searching in C++C++中用于快速搜索的数据结构
【发布时间】:2015-03-16 10:49:02
【问题描述】:

我需要将如下值存储在数据结构中,

id   x     y     z
0    0.1   0.1   0.1
1    0.2   0.1   0.6
2    0.01  0.3   0.1
.....

现在我需要匹配 x,y,z 双精度值并获取对应的 id(int) 值。我可能需要存储大约 400000 个值。我应该使用什么样的数据结构来进行有效的搜索? C++ 是否带有任何支持我的要求的内置结构。

【问题讨论】:

  • 构建一个包含xyz值的struct(比如foo)以及必要的谓词,然后使用std::map<foo, int>;假设您的id 可以表示为int。搜索将是 O(log N)。您唯一需要解决的是浮点比较,但这取决于xyz 的候选值是如何出现的。
  • 您如何测试doubles 的相等性?如果您使用 operator==abs(x-y) < threshold 之类的东西或其他东西,可能的答案会大不相同。
  • 这可能取决于您想要的性能。你关心插入时间还是只关心搜索?
  • 您可能正在寻找k-d tree,如果您想要查询的“最近点”(而不仅仅是查询本身,以防您不知道您在寻找什么,但需要最近的邻居)
  • 搜索会更重要,因为我只会插入一次但经常搜索。由于双值,我可能不得不使用 abs。

标签: c++ performance algorithm data-structures


【解决方案1】:

如果您对 NN 搜索不感兴趣,可以使用std::unordered_set。但是,您需要定义自己的哈希函数。

这是一个(可能很糟糕)的例子:

struct entry
{
    int id;
    double x, y, z;

    // constructor if needed, etc...
};

struct entry_hasher
{
    size_t operator()(const entry &e) const
    {
        std::hash<double> h;
        return h(e.x) ^ (h(e.y) << 1) ^ (h(e.z) << 2);
    }
};

std::unordered_set<entry, entry_hasher> entries;

否则,标准不提供能够进行几何查询的容器(如NN)。

【讨论】:

  • 什么?您是否要基于浮点值的哈希和两个浮点数的精确相等来进行搜索?这是一个糟糕的主意
  • OP 没有提到搜索容差的要求。
  • 对于浮点数,这始终是一项要求。 (他做到了,在 cmets 中)。
  • 为了精确比较,浮点数与整数同构(它们被设计为在不支持 FP 的旧数据库中工作)。不,这并不总是一个要求:在 FP 域上生成网格需要精确的算术,这是通过将浮点数视为稀疏定点数(扩展)来完成的。
  • 在处理浮点数时没有“精确”之类的东西,这才是重点。
【解决方案2】:

这对你来说可能是个坏消息,但我认为最适合你的目的是k-d tree,它没有在标准库中实现。

此数据结构允许您在多维空间(在您的情况下为 3d 空间)中搜索任何给定点的最近邻居。这将保证在处理浮点键时最有可能发生的舍入错误的容限。

但是,这个 DS 非常受欢迎,我相信您将能够找到它的在线实现。

【讨论】:

    【解决方案3】:

    如果您只需要进行精确搜索,那么哈希表 (unordered_map) 将是一个不错的选择。将键设为 tuple 或结构,将值设为 int id。

    如果您需要进行区间搜索(例如,找到最接近 x 的元素)并且您总是按顺序从 x,y,z 搜索,那么您将需要一个有序的数据结构。有序树 (map) 应该可以工作。使用三层嵌套的map,这样您就可以通过基本上使用mymap[x][y][z] 以及您想要应用的任何间隔规则来进行搜索。

    如果您需要更复杂的搜索,可以从任何元素开始,或者只知道后两个元素的搜索,那么您将需要一个多维有序数据结构,它可以用于划分维度世界空间用于对数搜索。一些例子是octtreek-d tree。据我所知,没有八叉树/k-d 树的标准库实现。这类数据结构有很多变体,例如,您可以使用跳过列表而不是树。

    【讨论】:

    • 什么?您是否要基于浮点值的哈希和两个浮点数的精确相等来进行搜索?这是一个可怕的想法。不,有序树不会简单地用于多个特征的区间搜索。
    • @amit a good hash(float, float, float) -> int 用“链式”哈希来解决冲突应该可以解决问题。无论如何,我们只需要一个整数“提示”来快速找到匹配项。
    • @user4419802 如果(例如)z1 != z2 但 abs(z1-z2 )
    • @amit 让我们举一个(不好的)例子:hash = round(x+y+z)(我假设 3*fabs(delta)
    • @user4419802 不,假设 x1=x2=y1=y2=0, z1 = 0.5+delta/2, z2=0.5-delta/2。这两个点将被拆分为两个哈希值。当您尝试使哈希分布更好时,发生这种情况的可能性会增加。
    【解决方案4】:

    您可以使用 OcTree (http://en.wikipedia.org/wiki/Octree)。它比基于二叉树的 std 中的任何容器都更快、更方便。您也不必担心索引或哈希函数。但是它会占用更多的内存。它甚至可以用于 NN(最近邻)搜索。另一种选择是Kd-tree (http://en.wikipedia.org/wiki/K-d_tree)。两者都不是 STD 的一部分。 KdTree 比 OctTree 需要更少的内存,有时甚至更快。您应该能够通过 google 找到 OcTree 或 KdTree 的良好 C++ 实现。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-03-09
      • 2011-10-27
      • 2018-10-12
      • 2015-10-24
      • 2017-03-31
      • 2015-11-10
      • 2011-08-20
      • 1970-01-01
      相关资源
      最近更新 更多