add non-working recursive merge algorithm

This commit is contained in:
Pavel Patsey
2025-01-18 23:17:47 +03:00
parent af91a066a1
commit feda229c78
2 changed files with 80 additions and 27 deletions
+75 -10
View File
@@ -1,4 +1,5 @@
import cProfile import cProfile
from collections import defaultdict
Node = tuple[int, int, int, int] Node = tuple[int, int, int, int]
@@ -113,16 +114,71 @@ def make_cidr4(ip, mask_len) -> str:
return f"{ip_address}/{mask_len}" return f"{ip_address}/{mask_len}"
def answer(nodes: list[Node], required_len: int) -> tuple[list[str], int]: def lift_lonely_node(nodes: list[Node], singles: list[Node]) -> list[Node]:
nodes = sort_nodes(nodes) # find single whose parent has the least added addresses
merged_nodes = merge_nodes(nodes, required_len) min_single, min_parent = singles[0], make_parent(singles[0])
for node in singles[1:]:
parent = make_parent(node)
if parent[2] < min_parent[2]:
min_single, min_parent = node, parent
cidr4s = [] new_nodes = [x for x in nodes]
sum_added_ips = 0 new_nodes.remove(min_single)
for ip_value, mask_len, added_ips, _ in merged_nodes: new_nodes.append(min_parent)
cidr4s.append(make_cidr4(ip_value, mask_len)) new_nodes = sort_nodes(new_nodes)
sum_added_ips += added_ips return new_nodes
return cidr4s, sum_added_ips
def merge_neighbors(
nodes: list[Node], neighbours: list[tuple[Node, Node]]
) -> list[Node]:
new_nodes = [x for x in nodes]
for a, b in neighbours:
parent = make_parent(a, b)
new_nodes.remove(a)
new_nodes.remove(b)
new_nodes.append(parent)
return sort_nodes(nodes)
def find_neighbours_singles(groups: defaultdict) -> tuple[list, list]:
neighbours = []
singles = []
for group in groups.values():
i = 0
while i < len(group) - 1:
a, b = group[i], group[i + 1]
ip_a, mask_len_a, _, parent_ip_a = a
ip_b, mask_len_b, _, parent_ip_b = b
if have_same_parent(mask_len_a, parent_ip_a, mask_len_b, parent_ip_b):
neighbours.append((a, b))
i += 2
else:
singles.append(a)
i += 1
if i == len(group) - 1:
singles.append(group[i])
return neighbours, singles
def make_groups(nodes: list[Node]) -> defaultdict:
groups = defaultdict(list)
for n in nodes:
groups[n[1]].append(n)
return groups
def merge_nodes_recursion(nodes: list[Node], required_len: int) -> list[Node]:
if len(nodes) <= required_len:
return nodes
groups = make_groups(nodes)
neighbours, singles = find_neighbours_singles(groups)
print(f"{len(nodes)=} {len(singles)=} {len(neighbours)=}")
if neighbours:
new_nodes = merge_neighbors(nodes, neighbours)
return merge_nodes_recursion(new_nodes, required_len)
new_nodes = lift_lonely_node(nodes, singles)
return merge_nodes_recursion(new_nodes, required_len)
def main(): def main():
@@ -131,7 +187,16 @@ def main():
data = get_data(file) data = get_data(file)
nodes = list(map(cidr4_to_node, data)) nodes = list(map(cidr4_to_node, data))
cidr4s, sum_added_ips = answer(nodes, required_len)
nodes = sort_nodes(nodes)
# merged_nodes = merge_nodes(nodes, required_len)
merged_nodes = merge_nodes_recursion(nodes, required_len)
cidr4s = []
sum_added_ips = 0
for ip_value, mask_len, added_ips, _ in merged_nodes:
cidr4s.append(make_cidr4(ip_value, mask_len))
sum_added_ips += added_ips
cidr4s_str = "\n".join(cidr4s) cidr4s_str = "\n".join(cidr4s)
print( print(
+5 -17
View File
@@ -2,15 +2,19 @@ import pytest
from cidr4_merger import ( from cidr4_merger import (
Cidr4MergerError, Cidr4MergerError,
answer,
cidr4_to_node, cidr4_to_node,
find_neighbours_singles,
get_group_with_max_mask_len, get_group_with_max_mask_len,
get_net_addr, get_net_addr,
get_parent_ip, get_parent_ip,
have_same_parent, have_same_parent,
lift_lonely_node,
make_cidr4, make_cidr4,
make_groups,
make_parent, make_parent,
merge_neighbors,
merge_nodes, merge_nodes,
merge_nodes_recursion,
reduce_nodes, reduce_nodes,
sort_nodes, sort_nodes,
) )
@@ -203,19 +207,3 @@ def test_merge_nodes():
) )
assert exc_info.type is Cidr4MergerError assert exc_info.type is Cidr4MergerError
assert str(exc_info.value) == "The top of the tree has no parent!" assert str(exc_info.value) == "The top of the tree has no parent!"
def test_answer():
assert answer(
[
(0, 2, 12, 0),
(2147483648, 2, 1, 2147483648),
(3221225472, 2, 2, 2147483648),
],
2,
) == (["128.0.0.0/1", "0.0.0.0/2"], 15)
with pytest.raises(Exception) as exc_info:
answer([(0, 2, 0, 0), (2147483648, 2, 0, 2147483648)], 1)
assert exc_info.type is Cidr4MergerError
assert str(exc_info.value) == "The top of the tree has no parent!"