【问题标题】:What search algorithm or a data structure would you suggest?你会建议什么搜索算法或数据结构?
【发布时间】:2012-05-30 09:52:22
【问题描述】:

我有大量的SortedSet<Long> 结构:

1, 2, 5, 8, 10, 35, 77, ...
5, 9, 35, 50, 132, ...
2, 4, 8, 15, 17, 23, ...
... hundreds of thousands of such rows...

我需要找到一个数字,比如50。在这个例子中(如果只有三组)它是77。集合的数量是巨大的 - 数十万。你会建议什么算法?

【问题讨论】:

  • 您的意思是要合并列表的给定值 (50) 之后的下一个值吗?
  • 是的,完全来自“合并列表”
  • 如果77出现在多个集合中怎么办?你关心哪一组,或者你只是想在任何一组中找到下一个最高的数字?另外,如果不同的集合包含 50 个呢?该实例是 50“下一个”,还是“下一个成员严格大于“当前”值”?您的问题未详细说明。
  • 您也没有提到集合是否会在查询之间更新。如果没有,只需创建一个合并的排序值集即可。
  • (1) 你能告诉我们每组的大小吗? (2) 您需要运行多少个这样的查询? (3) 集合可以在查询之间改变,还是一成不变?

标签: java algorithm search sorting


【解决方案1】:

如果我理解正确,这是我的想法:

Collection<SortedSet<Long>> sets = //...

long minAfter50 = Long.MAX_VALUE;
for (SortedSet<Long> set : sets) {
    final Long first = set.tailSet(51L).first();
    minAfter50 = Math.min(minAfter50, first);
}

这是一个想法:

  • 遍历所有输入集
  • 裁剪所有小于或等于 50 的值
  • 取裁剪集的第一个参数(保证大于50)
  • 计算上一步收集的最小值

更新(基于 @beerbajay 评论):如果 SortedSet 实际上是 TreeSet,则以下代码可能会执行得更好。我还要确保每组中都有任何大于 50 的值:

long minAfter50 = Long.MAX_VALUE;
for (TreeSet<Long> set : sets) {
    final Long higher = set.higher(50L);
    if (higher != null && higher < minAfter50) {
        minAfter50 = higher;
    }
}

【讨论】:

  • 这似乎是最有效的方法,因为所有的 SortedSet 都已创建。合并它们或创建任何其他数据结构肯定会降低效率。
  • 如果您使用TreeSet 作为您的SortedSet 实现,则可以通过使用higher() 来避免在tailSet() 中创建视图的成本。 first = set.higher(50l);
  • @beerbajay:我根据您的宝贵意见更新了我的答案,希望您不要介意
  • 是的。你不会找到更有效的实现方式。
  • 嗯...有两个变量:集合的数量 (m) 和它们的大小 (n)。这个解决方案是O(m log n)。很明显,您必须至少查看每个m 集合一次,而且很明显,您无法确定50 以上集合中的值小于O(log n)。这有点过分了,但我想我相信了。
【解决方案2】:

如果这是您允许的所有预计算,那么您唯一能做的就是在每个 SortedSet 上调用 tailSet 并找到最小值。

如果您允许一些额外的数据结构,最简单的做法是跟踪所有集合的并集,然后您只需调用 tailSet 即可。

我怀疑两者都不是您想要的答案。也许您可以更好地描述您的限制条件?

【讨论】:

  • 对,这些选项都不适合我。主要是因为它们太慢了。我在这里寻找一些技巧。我没有任何限制。
  • @Keith 的第二个选项是“技巧”。也就是说,使用不同的数据结构而不是排序集列表。例如,一组已排序的 (value, listID) 对。现在查找是 O(log(mn)) 对于 m 个 n 值列表而不是 O(m log n)。
  • 如果您没有任何约束,则将 HashMap 从每个值预计算到下一个更高的值。 O(1)。 (通过将所有值放入一个数组中进行预计算,对它们进行排序,然后在HashMap 中输入每个相邻的对。)
【解决方案3】:

set 实现为二叉搜索树,最大的数总是在最后。 您可以更轻松地搜索大于 50 的数字,始终获得每组中大于 50 的第一个数字。

【讨论】:

    猜你喜欢
    • 2023-03-20
    • 1970-01-01
    • 2017-11-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-12
    • 2010-12-19
    相关资源
    最近更新 更多