Algorithm 支持对一组二维点进行特定查询的数据结构

Algorithm 支持对一组二维点进行特定查询的数据结构,algorithm,Algorithm,我有一组2D点,我希望能够使用参数x_min和n进行以下查询:具有最大y的n点有哪些x_min 要在Ruby中重新措辞: class PointsThing def initialize(points) @points = points end def query(x_min, n) @points.select { |point| point.x > x_min }.sort_by { |point| point.y }.take(n) end end

我有一组2D点,我希望能够使用参数
x_min
n
进行以下查询:具有最大
y
n
点有哪些
x_min

要在Ruby中重新措辞:

class PointsThing
  def initialize(points)
    @points = points
  end

  def query(x_min, n)
    @points.select { |point| point.x > x_min }.sort_by { |point| point.y }.take(n)
  end
end
理想情况下,我的类还支持插入和删除操作


我想不出一种数据结构能让查询在不到O(|@点|)的时间内运行。有人知道吗?

如果您的数据没有排序,那么您别无选择,只能检查每个点,因为您无法知道是否存在另一个点,其中y大于所有其他点的y,并且对于该点,
x>x\u min
。简言之:如果你不全部检查,你就不知道是否应该包括另一点

在这种情况下,我假设不可能按照您的要求签入sub线性时间,因为您必须全部检查它们。搜索所有对象的最佳情况是线性

如果对数据进行了排序,那么最好的情况是恒定时间(所有n个点都是y最大的点),最坏的情况是线性的(所有n个点都是y最小的点)。平均情况会更接近常数,我想如果你的x和x_min在特定范围内都是随机的

如果您想将其缩放(也就是说,可以有较大的n值),那么您还需要对结果集进行排序,因为您需要对照它检查新的潜在点,并在插入时删除最小值(如果大小>n)。使用树,这可以是日志时间

所以,要做整个事情,最坏的情况是对于未排序的点,在这种情况下,您看到的是nlog(n)时间。排序点更好,在这种情况下,您可以查看log(n)时间的平均情况(再次假设x和x_min的值大致随机分布),这是次线性的


如果一开始不清楚为什么排序的点会有固定的搜索时间,我将在这里快速地讨论

如果y值最大的n个点都有
x>x_min
(最佳情况),那么您只需要从顶部抓取您需要的,因此这种情况很明显

对于平均情况,假设x和x_min大致随机分布,
x>x_min
的几率基本上是一半。对于任意两个随机数a和b,
a>b
b>a
一样可能为真。这与x和x_min是一样的
x>x_-min
x_-min>x
的概率相同,即概率为0.5。这意味着,对于您的分数,平均每检查一秒,您的
x>x_min
要求将得到满足,因此您将平均检查2n个点,以找到满足您标准的n个最高点。所以最好的情况是c时间,平均值是2c,这仍然是常数

但是,请注意,对于接近集合大小的n值,这隐藏了这样一个事实,即您正在遍历整个集合,基本上将其恢复到线性时间。所以,如果你假设n的随机值在你的集合的大小范围内,那么我关于时间常数的断言就不成立了

如果这不是一个纯粹的学术问题,而是出于某种实际需要,那就要视情况而定

(编辑)
我刚刚意识到,我的常量时间断言假设了一种数据结构,在这种结构中,您可以直接访问最高值,并可以按顺序访问较低的值。如果提供给您的数据结构不符合该描述,那么显然情况并非如此。

在这种情况下,一些预计算将有所帮助

首先以x_min为轴心元素对点集进行分区

然后,对于位于x_min右侧的一组点,基于y坐标构建max_堆

现在以以下方式运行查询:在构建的最大值堆上执行n个extract\u max操作

查询的运行时间为logx+log(X-1)+。。。。。日志(X-(n-1))

日志X:用于第一次提取最大值操作

日志X-1:用于第二次提取最大值操作,依此类推

X:原始最大堆的大小


即使在最坏的情况下,当您的n符号

p
为点集

top_y(n,x_min)
描述从
p
收集
n
点的查询,其中x坐标大于或等于'x_min'的点的最大y坐标

x_0
为点集中x坐标的最小值。通过点集
P
的x坐标集,将
x_0
右侧的x轴划分为一组左侧闭合、右侧打开的间隔
I_I
,使得
min(I_I)
P
第四个但最小的x坐标。将
x
的坐标秩
r(x)
定义为区间的索引
x
是元素,如果
x
,则定义为0

请注意,
r(x)
可以在
O(log#({I_I}))
中使用二叉搜索树进行计算

简单解决方案

  • 通过减少y坐标对点集进行排序,并在时间
    O(#p log#p)
    和空间
    O(#p)
    中保存此数组

  • 通过按顺序遍历此数组,跳过项
    A\u i:A\u i.x
    ,计算所有其他项,直到计数器达到
    n
    或您位于
    A
    的末尾,来处理每个查询
    top\y(n,x\u min)
    。此处理需要
    O(n)
    时间和
    O(1)
    空间

  • 注意,这可能已经足够了:查询
    top_y(n_0,a_0);a_0