用于稀疏数据查找的高效数据结构

时间:2014-06-25 07:08:54

标签: c++ algorithm

情况:

给出一些带坐标的点(x,y) 范围0&lt; x&lt; 100,000,000和0 < y <100,000,000

我必须找到最小的正方形,其边缘和内部至少包含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个点。

  3. 这是非常低效的时间。

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

4 个答案:

答案 0 :(得分:2)

在2个相对边上有点 - 如果没有,你可以将平方缩小1并仍然包含相同数量的点。这意味着边缘的可能坐标限于输入点的坐标。但是,输入点可能不在角落。 (对于最小的矩形,所有4个边上都会有点,因为你可以收缩一个尺寸而不改变另一个尺寸)

接下来要认识到的是,每个点将平面划分为4个象限,每个象限包含许多点。 (由于象限有一个像素重叠,这些可以加起来超过总点数)。可以说,NW(p)是点p西北的点数,即具有x>=px and y>=py的点数。然后,正方形中的点数为NW(bottomleft) + NW(topright) - NW(bottomright) - NW(topleft)

为所有输入点计算NW(p)相当容易。按xxy进行排序。最西北的点有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)排序。

答案 1 :(得分:1)

请查看http://en.wikipedia.org/wiki/Space_partitioning使用Divide-and-Conquer技术解决此问题的算法。这在多项式时间内绝对可以解决。


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

  • 在点上生成vornoi图以获取邻居信息。 [O(nlog(n))]
  • 现在使用动态编程,DP将类似于在2D阵列中找到最大子阵列的问题。这里不是数字之和,而是在它之前保留点数。

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

  

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

对于其邻域以及左侧和上方的所有点,您的重现将不得不改变,而不仅仅是上面的上方和左侧的点。

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

  • 您甚至可以先从最小的方块开始贪婪地开始,这样您就可以在找到合适的方块后立即结束搜索。


答案 2 :(得分:1)

rtree允许空间搜索,但没有stl实现,尽管sqlite允许绑定。这可以回答&#34;得到范围内的所有点&#34;,&#34; k最近邻居&#34;

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

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

O(x)构建结构的时间 O(X N log(X))搜索最小的簇

答案 3 :(得分:1)

注意:第二个问题有很多答案(这可能会带来更大的好处),但我只是指你的第一个问题,即在不改变算法的情况下使用什么数据。

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

  • 整体分配,这浪费了空间。
  • Underallocation,这会导致在向量增长到必要大小时进行复制。
  • 复制。