【发布时间】:2014-01-22 22:31:49
【问题描述】:
我有一个 int[] 数组,其中包含具有以下属性的值:
- 它们是排序的
- 它们是独一无二的(没有重复)
- 它们在已知范围 [0..MAX)
- MAX 通常比数组的长度大很多(比如 10-100x)
- 有时数字会均匀分布在整个范围内,但有时会有相当长的连续数字序列。我估计这两种情况之间的比例约为 50/50。
给定这个列表,我想有效地找到数组中特定值的索引(或者如果该值不存在,则查找下一个更高的值)。
我已经实现了直接二分搜索,其中区间二等分效果相当好,但我怀疑可以利用数据的性质/分布来更快地收敛到解决方案。
我对优化平均案例搜索时间很感兴趣,但重要的是,最坏的情况永远不会比 O(log n) 更糟,因为数组有时非常大。
问题:在一般情况下,有可能比普通的二分搜索做得更好吗?
编辑(澄清其他问题/cmets)
- O(log n) 中的常数绝对很重要。事实上,假设不可能有比 O(log n) 更好的算法复杂度,那么常数可能是唯一重要的事情.....
- 这通常是一次性搜索,因此虽然可以进行预处理,但它可能不值得。
【问题讨论】:
-
您搜索了多少次?将它们粘贴到
Map将为您提供O(1)搜索,但将使用O(n)进行设置。附言你不需要实现二分搜索Arrays.binarySearch完全符合你的要求。 -
如果真的有大块连续的数字(没有重复),你可以修改你的二分搜索来识别它何时到达一个(
x[end] - x[start] == end - start?),然后直接跳到解决方案.请记住,这种方法依赖于非常长的连续序列,否则您不会消除许多递归阶段。 -
您尝试过插值搜索吗? en.wikipedia.org/wiki/Interpolation_search
-
我认为 O(log n) 中的常数对你也很重要。正确的?为什么不做一个类似于二分查找的算法,而是每次将数组分成 3 或 4 个子数组呢?并对此进行一些实验。
-
@peter.petrov:如果你的插值是愚蠢的,那可能就是那么糟糕。这真的取决于数据。如果分布相当均匀,智能插值搜索将击败直接二进制。如果数据不是合理均匀分布,二分查找可能是更好的选择。 OP 说它可以是 50/50(均匀分布与长时间的连续值)。我会说需要对几个有代表性的数据集进行测试才能确定哪个更好。