【问题标题】:Efficient data structure for sparse data lookup用于稀疏数据查找的高效数据结构
【发布时间】:2014-06-25 07:08:54
【问题描述】:

情况:

给定一些坐标为 (x, y) 的点 范围 0

我必须找到在其边缘和内部至少包含 N 个点的最小正方形。

  1. 我使用矢量来存储坐标并搜索边长 minLength 到边长 maxLength 的所有正方形(在相关空间中应用蛮力)

    struct Point
    {
            int x;
            int y;
    };
    
    vector<Point> P;
    int minLength = sqrt(N) - 1;
    int maxLength = 0;
    
    //   bigx= largest x coordinate of any point
    //   bigy= largest y coordinate of any point
    //   smallx= smallest x coordinate of any point
    //   smally= smallest y coordinate of any point
    
    (bigx - smallx) < (bigy - smally) ? maxLength = (bigx - smallx) : maxLength = (bigy - smally);
    
  2. 对于我查找的每个正方形,遍历完整向量以查看其边缘和内部是否至少有 N 个点。

这在时间上效率很低。

第一季度。在不改变我使用的算法的情况下,我应该使用什么数据结构来提高时间效率?
Q2。这个问题的高效算法?

【问题讨论】:

  • 有趣的问题。我想知道这个问题是否是 NP 难的。
  • 您可能会在“n(或k)最近邻居”问题中找到一些有用的想法,其中unifrom norm 用于表示距离。
  • @NPE:一点也不。输入域可以排序,事实证明这是最难的部分。从那里开始计数。
  • NPE:当然不是,显然有一个多项式时间算法:给定一个解平方,我们可以缩小它,同时仍然包含相同的点,直到它的三个边包含集合中的一个点。因此,通过考虑所有 3 个点的子集,我们可以找到正方形。
  • This paper 为该问题提出了一个 O(n log n + kn log^2 k) 算法,其中 n 是点数,k 是必须在正方形

标签: c++ algorithm


【解决方案1】:

在 2 个相对的边缘上有点 - 如果没有,您可以将正方形缩小 1 并且仍然包含相同数量的点。这意味着边缘的可能坐标仅限于输入点的坐标。不过,输入点可能不在拐角处。 (对于最小矩形,所有 4 个边上都会有点,因为您可以缩小一个维度而不改变另一个维度)

接下来要实现的是,每个点将平面分为 4 个象限,每个象限包含多个点。 (由于象限有一个像素重叠,这些加起来可以超过点的总数)。假设 NW(p) 是点 p 西北部的点数,即具有x&gt;=px and y&gt;=py 的点数。那么一个正方形中的点数是NW(bottomleft) + NW(topright) - NW(bottomright) - NW(topleft)

计算所有输入点的NW(p) 相当容易。按x 对它们进行排序,对于x,按y 对它们进行排序。最西北点有NW(p)==0。如果下一个点在第一个点的东南方,则它可以有NW(p)==1,否则它有NW(p)==0。在此阶段跟踪 SW(p) 也很有用,因为您正在从西向东遍历点,因此它们不会从北向南排序。计算完NW(p),就可以确定O(1)中正方形S的点数了

回想一下,正方形的大小受到对边上需要点的限制。假设这些点位于左侧(西部)和右侧边缘 - 您仍然拥有按 x 顺序排序的点。首先假设左边缘位于最左边的 x 坐标处,然后看看右边缘必须是什么才能包含 N 个点。现在将左边缘移动到下一个 x 坐标并找到一个新的右边缘(因此是一个新的正方形)。这样做直到正方形的右边缘是最右边的点。

正方形也有可能被限制在y方向。只需对 y 方向的点进行排序并重复,然后选择两个结果之间最小的正方形。

由于您在 x 和 y 方向上线性运行,因此该部分只是 O(N) 并且主要因素是 O(N log N) 排序。

【讨论】:

  • "首先假设左边缘在最左边的 x 坐标处,然后看看右边缘必须是什么才能包含 N 个点。"我认为这不是微不足道的。正方形中的点数取决于正方形的垂直位置,而不仅仅是它的宽度。此外,我们无法证明正方形中的一个点必须在它的一个角上,所以我不知道如何执行此步骤
【解决方案2】:

查看http://en.wikipedia.org/wiki/Space_partitioning 了解使用分而治之技术解决此问题的算法。这绝对可以在多项式时间内解决。


另一种变体算法可以在以下几行中。

  • 在点上生成 vornoi 图以获取邻居信息。 [ O(nlog(n)) ]​​i>
  • 现在使用动态规划,DP将类似于在二维数组中找到最大子数组的问题。在这里,您将保留之前的点数,而不是数字的总和。

    2.a 基本上与此类似的递归将成立。 [ O(n) ]

正方形中从 (0,0) 到 (x,y ) 的元素数 = (元素数 从正方形 (0,0 到 ((x-1),y))+ (正方形中元素的数量 0,0 - ( x, y-1)) - ((0,0)中的元素数-((x-1),(y-1)))

您的重复周期必须针对其附近以及左侧和上方的所有点进行更改,而不仅仅是上面和左侧的点。

  • 一旦 DP 准备好,您可以在 O(1) 中查询一个 sqare 中的点。 另一个 O(n^2) 循环从所有可能的组合中查找并找到最小二乘。

  • 你甚至可以贪婪地从最小的方块开始,这样一找到合适的方块就可以结束搜索..


【讨论】:

    【解决方案3】:

    rtree 允许空间搜索,但没有 stl 实现,尽管 sqlite 允许绑定。这可以回答“获取范围内的所有点”,“k个最近的邻居”

    寻找具有最密集数据的区域,是一个类似于聚类的问题。

    遍历这些点并找到离每个点最近的 N 个条目。然后生成最小的圆 - 中心将是 Max(x) - min(x),Max(y) - min(y)。可以形成一个包含所有邻居的正方形,与圆形相比,正方形的边长在 2r 到 2sqrt(r) 之间。

    构建结构花费的时间 O(x) O(X N log(X)) 寻找最小的簇

    【讨论】:

      【解决方案4】:

      注意:您的第二个问题有很多答案(这可能会获得更大的好处),但我仅指您的第一个问题,即在不更改算法的情况下使用哪些数据。

      在那里,我认为您使用向量的选择已经相当不错了,因为通常向量提供最佳的有效负载/开销比率以及最快的迭代。为了找出具体的瓶颈,使用分析器,否则你只是猜测。但是,对于大型向量,有一些事情要避免:

      • 过度分配,这会浪费空间。
      • 分配不足,当向量增长到必要的大小时,这会导致复制。
      • 正在复制。

      【讨论】:

        猜你喜欢
        • 2017-08-27
        • 2018-08-13
        • 2020-12-01
        • 2010-11-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多