【问题标题】:need an algorithm for collapsing netblock ranges into lists of superset ranges需要一种将网络块范围折叠成超集范围列表的算法
【发布时间】:2010-09-14 01:20:51
【问题描述】:

我的数学让我失望了!我需要一种将网络范围缩小为超集的有效方法,例如如果我输入 IP 范围列表:

  • 1.1.1.1 到 2.2.2.5
  • 1.1.1.2 到 2.2.2.4
  • 10.5.5.5 到 155.5.5.5
  • 10.5.5.6 到 10.5.5.7

我想返回以下范围:

  • 1.1.1.1 到 2.2.2.5
  • 10.5.5.5 到 155.5.5.5

注意:输入列表没有排序(尽管它们可能是?)。执行此操作的天真方法是检查列表中的每个范围以查看输入范围 x 是否是子集,如果是,则不插入范围 x。但是,每当您插入新范围时,它可能是现有范围的超集,因此您必须检查现有范围以查看它们是否可以折叠(例如,从我的列表中删除)。

【问题讨论】:

  • 范围会不相交吗?如果不是,您希望您的算法如何处理重叠范围,其中许多子范围可能是其中的一部分?
  • 使用您描述的“朴素”算法有什么问题?对我来说似乎很好......
  • 好问题!用户可以输入他们想要的任何范围,因此不能保证它们是不相交的。实际上,如果所有连续的范围都可以合并为一个,那就太好了。
  • 致 MikeF:如果我每次插入时都必须与列表中的每个现有项目进行比较,那么天真的方法可能会像废话一样慢。我们有一些客户的范围 > 40k(并且他们想要添加更多!)。我不想进行 40k 比较来进行插入。
  • 如前所述,幼稚的方法也无法处理两个范围重叠但一个范围不完全包含在另一个范围内的情况。

标签: algorithm


【解决方案1】:

这是段计算的联合。最佳算法(在 O(nlog(n)) 中)包括执行以下操作:

  1. 对列表 L 中的所有端点(起点和终点)进行排序(每个端点都应该知道它所属的段)。如果端点等于起点,则应认为起点小于起点。
  2. 从左到右遍历排序列表L并保持数字LE-RE,其中LE是您已经通过的左侧端点的数量,并且RE 是您已经通过的正确端点数。
  3. 每次 LE-RE 达到零时,您就处于连接的线段并集的末尾,并且您知道您之前看到的线段的并集(因为之前返回零) 是一个超集。
  4. 如果您还保持了最小值和最大值,则在每次归零之间,您就有了超集的界限。

最后,您会获得一个排序的不相交超集列表。尽管如此,两个超集 A 和 B 可以相邻(A 的端点正好在 B 的起点之前)。如果您希望 A 和 B 合并,您可以通过简单的后处理步骤或稍微修改步骤 3 来做到这一点:当 LE-RE 达到零时,您会认为它是一个结束仅当 L 中的下一个元素不是您当前元素的直接后继时才具有超集。

【讨论】:

    【解决方案2】:

    您知道可以轻松地将 IPv4 地址转换为 int 数字(int32 数字),是吗?使用 int 数字要容易得多。所以基本上每个地址都是 0 到 2^32 范围内的数字。每个范围都有一个起始编号和一个结束编号。你的例子

    1.1.1.1 to 2.2.2.5
    1.1.1.2 to 2.2.2.4
    

    可以写成

    16,843,009 to 33,686,021
    16,843,010 to 33,686,020
    

    所以很容易看出一个范围是否在另一个范围内。如果给定以下条件,则一个范围完全在另一个范围内

    startIP2 >= startIP1 && startIP2 <= endIP1 &&
    endIP1 >= startIP1 && endIP2 <= endIP1
    

    在这种情况下,范围 startIP2-endIP2 完全在 startIP1-endIP1 内。如果只有第一行为真,则 startIP2 在 startIP1-endIP1 范围内,但 end 超出范围。如果只有第二行为真,则 endIP 在范围内,但起始 IP 在范围外。在这种情况下,如果只有一行为真,则需要在开头或结尾扩展范围。如果两行都为假,则范围完全不相交,在这种情况下,它们是两个完全独立的范围。

    【讨论】:

      【解决方案3】:

      您需要做的只是检查重叠范围。如果两个范围重叠,则它们将合并为一个范围。如果一个范围的右侧大于另一个范围的左侧,则范围重叠。

      【讨论】:

      • 根据您的定义,10.1.1.0-10.2.2.255(一个范围)与4.4.4.0-4.4.4.255(另一个范围)重叠。
      【解决方案4】:

      好的,我的同事想出了这个答案,我认为这非常好。如果您发现任何问题,请告诉我:

      • 按StartingIP对IP范围排序
      • 对于要插入的每一行“x”:
        • 如果列表中有前一行“y”,则获取:
          • 如果 x 和 y 是连续的,则将 y 扩展到 x 的 EndingIP
          • 否则,如果 x.StartingIP y.EndingIP,则将 y 扩展到 x.EndingIP
          • 否则,如果 x 是 y 的子集,则什么也不做
          • 否则,创建一个新范围
        • 否则,创建一个新范围并插入到列表中

      【讨论】:

      • 是的,按照这些思路肯定可以做到。
      • 顺便说一句,完全在一个列表上操作似乎比从初始范围列表创建第二个更简单。
      猜你喜欢
      • 2012-06-03
      • 2011-02-20
      • 2014-03-14
      • 1970-01-01
      • 2013-02-21
      • 1970-01-01
      • 1970-01-01
      • 2015-01-04
      • 1970-01-01
      相关资源
      最近更新 更多