您可以使用广度优先搜索按级别查找所有节点,然后从不是父节点或叶子节点的级别中选择节点,并由左右一个节点缓冲:
from collections import deque, defaultdict
def non_exposed(tree):
d, q = defaultdict(list), deque([(0, tree)])
while q:
d[(v:=q.popleft())[0]].append(v[1])
q.extend([*filter(lambda x:x[-1], [(v[0]+1, v[1].left), (v[0]+1, v[1].right)])])
return [j for a, b in d.items() for j in b[1:-1] if a and any([j.left, j.right])]
演示:
import random
class Tree:
def __init__(self, v, left = None, right = None):
self.v, self.left, self.right = v, left, right
def __repr__(self):
return f'Tree({self.v}, {self.left}, {self.right})'
def get_tree(n):
v = random.randint(1, 10)
return None if not n else Tree(v, left=get_tree(n-1), right=get_tree(n-1))
test_tree = get_tree(5)
results = [i.v for i in non_exposed(test_tree)]
print(len(results))
输出:
8
解释:
get_tree 构建了一个完整的n 级别的“二进制”树。在这样的树中,完整节点的总数将为sum(pow(2, i) - 2 for i in range(2, n-1)),因此当n=5 时,结果为8。