getTrees = {
function *getTrees(nodeCount, leafCount, maxIndex = Infinity) {
if (nodeCount === 1) {
if (leafCount === 1) {
yield { tree: 1, index: 0 };
}
} else {
let i = 0;
for (const children of remainingChildren(nodeCount - 1, leafCount)) {
if (i > maxIndex) break;
yield { tree: children, index: i++ };
}
}
}
function *remainingChildren(nodesLeft, leavesLeft, [prevNodeCount, prevLeafCount, prevIndex] = [0, 0, 0]) {
if (nodesLeft === 0 && leavesLeft === 0) {
yield [];
return;
}
if (nodesLeft < leavesLeft) {
return;
}
const minNodeCount = prevNodeCount || 1;
for (let nodeCount = minNodeCount; nodeCount <= nodesLeft; nodeCount++) {
const minLeafCount = nodeCount === prevNodeCount ? prevLeafCount : 1;
for (let leafCount = minLeafCount; leafCount <= leavesLeft; leafCount++) {
if (leavesLeft === leafCount && nodesLeft > nodeCount) continue;
const trees = (nodeCount === prevNodeCount && leafCount === prevLeafCount) ?
getTrees(nodeCount, leafCount, prevIndex) : getTrees(nodeCount, leafCount);
for (const { tree, index } of trees) {
for (const rest of remainingChildren(
nodesLeft - nodeCount,
leavesLeft - leafCount,
[nodeCount, leafCount, index])) {
yield [tree, ...rest];
}
}
}
}
}
return getTrees;
}