在PHP中获取可用CIDR网段:确定未使用子网的最优算法
解决父子网未使用子网的最优算法实现
核心思路梳理
你一开始的思路其实非常靠谱——从父网出发,逐步拆分并排除已使用子网,这个方法叫「分割-排除法」,是处理这类子网计算问题效率很高的方案。我来把子网拆分的具体逻辑拆解开,帮你补全算法的细节。
子网拆分的核心操作与流程
首先得明确几个基础操作,这是拆分的前提:
- 判断子网包含关系:要验证子网A是否包含子网B,需确认B的网络地址落在A的地址范围内,且B的前缀长度≥A的前缀长度。
- 拆分单个子网为两个子子网:比如把
10.0.0.0/24拆成两个/25,就是10.0.0.0/25和10.0.0.128/25;拆分/25则得到两个/26——本质是把当前子网主机位的最高位分别设为0和1,生成两个新的子网。
接下来是完整的算法执行流程:
- 初始化
$unused数组,只放入父子网$parent。 - 遍历每个已使用的子网
$used_subnet:- 遍历
$unused数组,找到包含$used_subnet的唯一目标子网$target(因为$unused里的子网是不重叠且完全覆盖父网的,所以只会有一个)。 - 如果
$target和$used_subnet完全相等,直接从$unused中移除$target,跳过后续步骤。 - 如果
$target的前缀长度比$used_subnet小,开始循环拆分:- 将
$target拆分为两个下一级的子网(比如/24拆成两个/25)。 - 从
$unused中移除$target,把拆分后的两个子网加入$unused。 - 再次检查这两个新子网,找到包含
$used_subnet的那个,继续拆分,直到拆分出的子网前缀长度和$used_subnet一致。
- 将
- 此时
$unused里会有一个和$used_subnet完全匹配的子网,将其移除即可。
- 遍历
- 遍历结束后,
$unused中的就是最精简的未使用子网集合。
补全后的伪代码(含拆分逻辑)
function get_unused_subnets(parent, used): unused = [parent] # 优化:先按前缀长度从大到小排序已使用子网,减少拆分次数 sort used in descending order of prefix length for each used_subnet in used: target = find_containing_subnet(unused, used_subnet) if target == used_subnet: unused.remove(target) continue # 循环拆分直到target的前缀与used_subnet一致 while target.prefix_length < used_subnet.prefix_length: subnet1, subnet2 = split_subnet(target) # 替换unused中的target为两个子子网 unused.remove(target) unused.append(subnet1) unused.append(subnet2) # 更新target为包含used_subnet的子子网 target = find_containing_subnet([subnet1, subnet2], used_subnet) # 移除匹配的已使用子网 unused.remove(target) # 可选:按网络地址排序,让结果更规整 sort unused by network address return unused # 辅助函数:拆分子网为两个下一级子网 function split_subnet(subnet): network = subnet.network_address # 比如10.0.0.0 prefix = subnet.prefix_length # 比如24 host_bits = 32 - prefix step = 1 << (host_bits - 1) # 计算拆分步长:2^(主机位-1) network1 = network network2 = network + step return (Subnet(network1, prefix+1), Subnet(network2, prefix+1)) # 辅助函数:从列表中找到包含目标子网的条目 function find_containing_subnet(subnets, target): for subnet in subnets: if subnet.network_address ≤ target.network_address and (target.network_address + target.host_count) ≤ (subnet.network_address + subnet.host_count): return subnet return null
额外优化建议
- 二分查找优化:如果维护
unused数组按网络地址排序,find_containing_subnet可以用二分查找替代遍历,大幅提升大数量子网场景下的效率。 - 相邻子网合并(可选):如果你的场景允许合并相邻的同前缀子网(比如两个相邻的
/29合并为/28),可以在最后对$unused做一次合并操作,让结果更精简——不过你的示例输出没有做合并,所以这一步看业务需求。
用你给出的示例测试:初始unused = ['10.0.0.0/24'],依次处理三个已使用子网后,最终就能得到你给出的$unused结果。
内容的提问来源于stack exchange,提问作者James
相关产品推荐
相关产品推荐

