【问题标题】:Efficient way to store multiple ranges of numbers for future searching存储多个数字范围以供将来搜索的有效方法
【发布时间】:2016-04-20 15:52:51
【问题描述】:

我有一个包含 IP 地址范围的文本文件。我使用ip2long 将地址转换为长整数,以便我可以轻松检查给定地址是否在范围内。但是,我正在寻找一种有效的方法来存储这些范围,然后搜索以查看 IP 地址是否存在于任何范围内。

我正在考虑的当前方法是创建一个对象,该对象具有范围的低端和高端,并带有一个函数来检查值是否在范围内。我会将这些对象存储在一个列表中并检查每个对象。但是,我觉得这可能有点效率低下,并且随着列表的增加可能会变慢。

有没有比我想的更好的方法?

【问题讨论】:

  • 你当然可以使用 Guava RangeSet...

标签: java algorithm performance


【解决方案1】:

以下数据结构之一可能会对您有所帮助:

分段树

来自Wikipedia (Implementation):

是一种用于存储区间或段的树形数据结构。它允许查询哪些存储段包含给定点。


区间树

来自Wikipedia (Implementation):

是一个保存区间的树形数据结构。具体来说,它允许人们有效地找到与任何给定区间或点重叠的所有区间。


范围树

来自Wikipedia (Implementation):

是一个有序的树数据结构,用于保存点列表。它允许有效地报告给定范围内的所有点。

【讨论】:

    【解决方案2】:

    假设范围不重叠,否则您可以将它们合并为一个范围。

    然后创建一个越来越有序的begin1, end1, begin2, end2, ... 数组。 其中begini 包含在范围内,endi 就在范围之后。

    现在进行二分搜索,然后:

    int pos = ... .binarySearch ...
    boolean found = pos >= 0;
    if (!found) {
        pos = ~pos;
    }
    boolean atBegin = pos % 2 == 0;
    boolean insideRange = (found && atBegin) || (!found && !atBegin);
    //Equivalent: boolean insideRange = found == atBegin;
    

    查找测试是O(log N)。初始数组的创建要复杂得多。

    Java binarySearch 在找到时提供索引,在未找到时提供~index(反码,


    附录:我认为以上内容可以“巧妙地”由

    组成
    boolean insideRange = (Arrays.binarySearch(...) & 1) == 0;
    

    虽然肯定需要解释性评论。我把它留给读者。

    【讨论】:

    • 几乎可以肯定不是 O(log N)。您说对范围进行排序,这意味着至少 O(N log N) 如果它们在他的文本文件中没有完美排序。此外,即使扫描每个范围以制作数组也是 O(N)。我知道二进制搜索是 O(log N),但是这样说(在我看来)是误导性的,因为你似乎在谈论你的解决方案是 O(log N)。否则,很好的解决方案。
    • @nhouser9 我的意思是检索,考虑到预先构建的 IP 数组。不过话说得好。
    • @nhouser9 我认为 Joop Eggen 的意思是查找
    • 当然他的意思是查找(我什至说我知道他在我的评论中是这个意思)。但是我认为如果你的解决方案实际上不是 O(log N),那么在回答他们的问题时告诉某人“这是 O(log N)”是一种误导。谁在乎算法中最快的部分是否是 O(log N)?任何关心时间复杂度的人都会关心算法中最慢的部分。充其量,“这是 O(log N)”这行是无关紧要的 - 最坏的情况是它非常具有误导性。
    • 我不能保证范围不会重叠。我不管理列表,所以一切皆有可能。另外,范围不是按顺序排列的,所以我也必须排序。
    猜你喜欢
    • 2017-03-24
    • 1970-01-01
    • 2012-11-15
    • 2019-05-05
    • 2016-10-15
    • 1970-01-01
    • 2018-11-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多