いくつかの異なるタイプのツリー ノードがあり、それぞれが 0 から 5 の子を持つ可能性があります。深さ <= N の考えられるすべてのツリーを生成するアルゴリズムを見つけようとしています。ノードに変更を加えるたびに新しいサブツリーが公開される(または古いサブツリーが削除される)可能性があるため、ツリーを再帰的にたどる方法を理解するのに苦労しています。
4 に答える
これは私が書いたPythonプログラムで、あなたが求めていることを実行すると思います。開始ノードを指定すると、可能なすべてのツリーが返されます。基本的に、これはビット操作によるトリックに要約されます。ノードに 5 つの子がある場合、各子が個別にサブツリーに存在する場合と存在しない場合があるため、2 5 = 32 の異なるサブツリーが存在する可能性があります。
コード:
#!/usr/bin/env python
def all_combos(choices):
"""
Given a list of items (a,b,c,...), generates all possible combinations of
items where one item is taken from a, one from b, one from c, and so on.
For example, all_combos([[1, 2], ["a", "b", "c"]]) yields:
[1, "a"]
[1, "b"]
[1, "c"]
[2, "a"]
[2, "b"]
[2, "c"]
"""
if not choices:
yield []
return
for left_choice in choices[0]:
for right_choices in all_combos(choices[1:]):
yield [left_choice] + right_choices
class Node:
def __init__(self, value, children=[]):
self.value = value
self.children = children
def all_subtrees(self, max_depth):
yield Node(self.value)
if max_depth > 0:
# For each child, get all of its possible sub-trees.
child_subtrees = [list(self.children[i].all_subtrees(max_depth - 1)) for i in range(len(self.children))]
# Now for the n children iterate through the 2^n possibilities where
# each child's subtree is independently present or not present. The
# i-th child is present if the i-th bit in "bits" is a 1.
for bits in xrange(1, 2 ** len(self.children)):
for combos in all_combos([child_subtrees[i] for i in range(len(self.children)) if bits & (1 << i) != 0]):
yield Node(self.value, combos)
def __str__(self):
"""
Display the node's value, and then its children in brackets if it has any.
"""
if self.children:
return "%s %s" % (self.value, self.children)
else:
return str(self.value)
def __repr__(self):
return str(self)
tree = Node(1,
[
Node(2),
Node(3,
[
Node(4),
Node(5),
Node(6)
])
])
for subtree in tree.all_subtrees(2):
print subtree
テスト ツリーのグラフィカルな表現を次に示します。
1 / \ 2 3 /|\ 4 5 6
そして、プログラムを実行した結果は次のとおりです。
1 1 [2] 1 [3] 1 [3 [4]] 1 [3 [5]] 1 [3 [4, 5]] 1 [3 [6]] 1 [3 [4, 6]] 1 [3 [5, 6]] 1 [3 [4, 5, 6]] 1 [2, 3] 1 [2, 3 [4]] 1 [2, 3 [5]] 1 [2, 3 [4, 5]] 1 [2, 3 [6]] 1 [2, 3 [4, 6]] 1 [2, 3 [5, 6]] 1 [2, 3 [4, 5, 6]]
もしよろしければ、これを別の言語に翻訳できます。指定しなかったので、Python を使用しました。Python のリスト内包表記を大いに活用したので、コードは Java や C++ などでもう少し冗長になります。
要素を多次元配列に追加し、ツリーが完成するまでその関数を再度呼び出す for ループを含む関数を作成できます。あなたがどの言語を好むかわからないため、例を提供することはできません。
ノード タイプ間の唯一の違いが子の数である場合、最大数の子を持つノード タイプのみを使用してすべての可能なツリーを生成すると、等しいか少ない子を持つノードの任意の組み合わせに対してもすべての可能なツリーが生成されます。
それはちょっと一口です...
別の言い方をすれば、5 つの子が最大の場合、5 つの子ノードのみで構成される可能なツリーの一部には、たとえば 2 つの実際の子と 3 つの null ポインターを持つノードがあります。これは、子ノードが 2 つしかないノードを持つことと実質的に同じです。