K最近元素

时间:2019-06-02 14:16:43

标签: arrays data-structures tree heap

这是一个面试问题。

宇宙中有数十亿颗恒星。您将使用哪种数据结构来回答查询 “给我最靠近地球的k星”。

我想到堆。正如我们可以在O(n)中进行堆化并在O(logn)中获得n_smallest一样。是否有更好的数据结构适合此目的?

2 个答案:

答案 0 :(得分:1)

假设输入不能同时全部存储在内存中(这将是一个挑战!),而是宇宙中恒星的-就像您将得到的迭代器之类的东西-您可以从使用最大堆(而不是首先想到的最小堆)中受益。

一开始,您只需要按堆中的星星(按它们与地球的距离来确定)即可,直到您的堆中有 k 个条目。

从那时起,如果新星的距离大于堆根的距离,则可以忽略它。当它比根星更近时,用新星代替根,然后对其进行筛选以恢复堆属性。

您的堆的增长不会超过 k 个元素,并且始终由您处理过的 k 个最近的恒星组成。

一些评论:

  • 因为它是最大堆,所以您不知道哪颗是最近星(恒定时间)。当您停止该算法,然后一个接一个地拔出根节点时,您将得到按距离降序排列的 k 个最近的星星。

  • 由于可观察的(!)宇宙估计有10 21 个恒星,因此您需要最好的超级计算机之一(1 exaFLOPS)来处理所有这些超级计算机。明星在合理的时间。但是至少该算法只需要在内存中保留 k 个星星即可。

答案 1 :(得分:0)

您要遇到的第一个问题是规模。仅银河系中就有约1000亿至4000亿颗恒星。估计有100亿个星系。如果我们假设每个星系平均有1000亿颗恒星,那么这就是宇宙中10 ^ 19颗恒星。您不太可能拥有该内存。即使您确实有足够的内存,也可能没有时间。假设您的heapify操作每秒可以进行十亿次迭代,则将花费一万亿秒(31,700年)。然后必须增加从堆中删除最小的k所需的时间。

通过使用多个线程或进程来构建堆,不太可能获得重大改进。

此处的关键是预处理数据并将其存储为一种形式,以便您快速消除大多数可能性。最简单的方法是按照与地球的距离排序列出恒星。因此,索尔(Sol)将在列表的顶部,普罗克西玛(Proxima Centauri)在其后,等等。然后,获取最近的k星将是O(k)运算:只需从列表中读取前k个项即可。

但是,排序后的列表很难更新。更好的选择是k-d tree。更新更加容易,并且与k个最近的邻居仍然相当快捷。