在许多排序数组中进行二进制搜索

时间:2013-10-01 13:42:19

标签: algorithm sorting

我有很多带有排序数据的数组。我需要在这个数组中执行二进制搜索。如果此数组中的键范围不相交,则可以按范围对数组进行排序,然后像单个数组一样执行二进制搜索。但就我而言,此数组中的键范围可能会重叠。在这种情况下,只能执行过滤以排除某些数组,然后对其他部分进行排序。 在我的情况下,大多数数组不重叠,因此大多数情况下,过滤只返回一个数组,但坏数据仍然可能破坏性能。

在这种情况下是否可以使用更好的算法?可以稍微修改数组,添加一些元数据或链接到其他数组。

更新 此阵列是由磁盘存储支持的数据页。我使用内存映射文件。我可以非常快速地对页面内的数据进行排序,因为复制不涉及此过程。但要合并两个页面,我需要在页面之间复制大量数据。 我有非常大量的数据,太字节!但每页只有8Mb,因此可以快速搜索。新页面不时添加到存储中。页面包含时间序列数据,因此它已经部分排序,并且新数组在大多数情况下不会与旧数据重叠。

5 个答案:

答案 0 :(得分:4)

  

如果此数组中的键范围不相交,则可以按范围对数组进行排序,然后像单个数组一样执行二进制搜索。但就我而言,这个数组中的键范围可能会重叠。

你仍然可以对它们进行排序。您可以使用interval tree来存储它们,并在对数时间内检索待搜索的数组,而不是按边界对所有数组进行天真过滤。由于你有很多阵列,而且它们之间很少相互重叠,这应该会显着提升性能。

答案 1 :(得分:2)

如果您只计划执行一些查询,我认为您无法改进算法 - 我相信它已经相当不错了。如果您希望执行大量查询,我建议您将数组合并到一个数组并对其执行二进制搜索。合并是与合并排序一部分相同的算法,并且是线性的。因此,只要查询数量弥补线性合并,就值得。

答案 2 :(得分:2)

8MB页面中的太字节意味着你有几百万页的句柄。每个页面都在内部排序,页面中的值可以(很少,但可以)相互重叠。

我希望找到正确页面的影响更大,然后在页面中找到正确的条目。

因此,我建议采用以下方法:

  • 维护每页最低和最高键的数组(lowestPageKeyhighestPageKey)。
  • 进行二元搜索以获取拟合页面并在页面内进行第二次二进制搜索。
  • 为了在searchKey上找到拟合页面,在元数据中进行范围拟合二进制搜索。
    • 使用条件lowestPageKey <= searchKey <= highestPageKey查找正确的页面。
    • 如果lowestPageKey > searchKey您可以继续使用数组的下半部分
    • 如果highestPageKey < searchKey您可以继续使用数组的较高部分

通过这种方式,您可以找到正确的页面,并可以在找到的页面中发出第二个二进制搜索。

我身边还有一个问题:如果页面中的值重叠,您可以找到包含搜索关键字的多个条目(或多个页面)。在这种情况下你期待什么?一个页面/条目随机,所有页面/条目,第一页/最后一页/条目或错误消息?

答案 3 :(得分:2)

你暗示你对大多数静态数据有很多疑问,所以我会假设。你走在正确的轨道上。只是不排除重叠数组。跟踪重叠。这是怎么回事。首先编译范围索引。如果阵列是不相交的,那么它们就是块。如果有两个数组重叠:

|     A    |
     |       B       |

分为三个范围:

| A  | AB  |   B     |

如图所示,范围索引只记录低边界和高边界以及覆盖范围的数组列表。

现在搜索索引(在内存中)以确定要搜索的数组。然后去搜索所有这些。作为进一步优化,可以使用块边界来限制数组搜索。换句话说,如果你得到上面的块AB,你可以在搜索时排除A的一部分和B的一部分。

如何有效地编译和更新索引?我建议interval tree。此页面提供伪代码。如果您使用C ++进行编程,则可以使用the relevant Boost library来获得良好的优势。

对于间隔树,每个数组都是一个间隔。使用点查询树时,将返回所有相关间隔。这些是大量搜索的数组。

答案 4 :(得分:1)

维护多组具有不相交范围的数组。

执行二进制搜索时,可以在这些组上并行执行,也可以基于最小的第一组对其进行尝试。

对于每个组,保持范围,每当新页面到达时,将其附加到与此新页面没有不相交范围的最大组。如果页面不属于任何组,请创建一个新组。

正如你所说,大多数时间范围不重叠,拥有这些额外组的机会相当少,但算法可以在发生这种异常时适应。