Spaces:
Running
Running
"""Generic tools for working with trees.""" | |
from math import ceil, log | |
def build_n_ary_tree(leaves, n): | |
"""Build N-ary tree from sequence of leaf nodes. | |
Return a list of lists where each non-leaf node is a list containing | |
max n nodes. | |
""" | |
if not leaves: | |
return [] | |
assert n > 1 | |
depth = ceil(log(len(leaves), n)) | |
if depth <= 1: | |
return list(leaves) | |
# Fully populate complete subtrees of root until we have enough leaves left | |
root = [] | |
unassigned = None | |
full_step = n ** (depth - 1) | |
for i in range(0, len(leaves), full_step): | |
subtree = leaves[i : i + full_step] | |
if len(subtree) < full_step: | |
unassigned = subtree | |
break | |
while len(subtree) > n: | |
subtree = [subtree[k : k + n] for k in range(0, len(subtree), n)] | |
root.append(subtree) | |
if unassigned: | |
# Recurse to fill the last subtree, which is the only partially populated one | |
subtree = build_n_ary_tree(unassigned, n) | |
if len(subtree) <= n - len(root): | |
# replace last subtree with its children if they can still fit | |
root.extend(subtree) | |
else: | |
root.append(subtree) | |
assert len(root) <= n | |
return root | |