需要一种将网块范围折叠为超集范围列表的算法
我的数学赋使我失望!我需要一种将网络范围缩小到超集的有效方法,例如如果我输入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。但是,无论何时插入新范围,它都可能是现有范围的超集,因此我们必须检查现有范围,以查看它们是否可以折叠(例如,从我的列表中删除)。
解决方案
我们只需要检查重叠范围即可。如果两个范围重叠,则它们将合并为一个范围。如果一个范围的右侧大于另一个范围的左侧,则范围重叠。
好吧,我的同事想出了这个答案,我认为这是非常出色的。如果我们有任何问题,请告诉我:
- 通过启动IP来订购IP范围
- 否则,如果x.StartingIP <= y.StartingIP和x.EndingIP> y.EndingIP,则将y扩展到x.EndingIP
- 否则,如果x是y的子集,则什么也不做
- 否则,创建一个新范围
- 否则,创建一个新范围并插入列表
这是段计算的并集。最佳算法(在O(nlog(n))中)包括以下步骤:
- 在列表L中对所有端点(起点和终点)进行排序(每个端点应该知道其所属的段)。如果端点等于起点,则应认为起点小于端点。
- 从左到右浏览排序列表L并保持数字LE-RE,其中LE是我们已经通过的左端点的数量,RE是我们已经通过的右端点的数量。
- 每次LE-RE达到零时,我们就处于连接的段并集的末尾,并且我们知道我们之前看到的段的并集(因为前一个返回零)是一个超集。
- 如果我们还保持了每次返回零之间的最小值和最大值,则我们具有超集的边界。
最后,我们获得不相交超集的排序列表。尽管如此,两个超集A和B可以相邻(A的端点恰在B的起点之前)。如果希望将A和B合并,则可以通过简单的后处理步骤,也可以通过略微修改步骤3来完成此操作:当LE-RE达到零时,仅当其中的下一个元素时,才将其视为超集的结尾。 L不是我们当前元素的直接后继。
我们知道可以轻松地将IPv4地址转换为int编号(int32编号),对吗?使用整型数要容易得多。因此,基本上每个地址都是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范围内,但结束范围超出范围。如果仅第二行为真,则endIP在范围内,但起始IP不在范围内。在这种情况下,如果只有一行是正确的,则需要在开头或者结尾处扩大范围。如果两条线都为假,则范围是完全不相交的,在这种情况下,它们是两个完全独立的范围。