質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

3回答

1383閲覧

Pythonで木構造の葉の最小の深さを求める方法

aya0425

総合スコア8

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

0クリップ

投稿2021/11/29 02:13

編集2021/11/29 03:45

前提・実現したいこと

プログラミング初心者です.
木構造の葉の最小の深さを再帰プログラミングを用いて求めようとしています。
例えば、以下の木構造では最小の深さはB:8の1となります。

A: 2 │ ├──B: 8 │ └──C: 5 │ ├──D: 11 │ │ │ └──F: 5 │ └──E: 6

発生している問題・エラーメッセージ

ところが、現状のコードでは最小の深さが5である以下の木構造でも出力が1となってしまいます。
自力では長時間考えても糸口が掴めませんでした。どなたか解決策を教えていただけますでしょうか。

A: 1 │ └──A: 2 │ └──E: 3 │ └──A: 4 │ └──I: 5 │ └──A: 6

現状のソースコード

Python

1def min_depth_func(tree): #treeは木構造のインスタンス、引数はtreeのみ 2 if tree.num_children() == 0: 3 print("base route") 4 return 1 5 6 num_depth = 0 7 depth_lst = [] 8 for kid in tree.children: 9 num_depth += min_depth_func(kid) 10 depth_lst.append(num_depth) 11 min_depth = min(depth_lst) 12 return min_depth

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

考え方の参考として、コード例を挙げておきます。考え方を示すことが目的なので、この回答ではツリーが以下のようなJSONで与えられ、これをパースして得られるdictを処理対象のツリーとします。

json

1{ 2 "id":1, 3 "children":[ 4 { 5 "id":8 6 }, 7 { 8 "id":5, 9 "children":[ 10 { 11 "id":11, 12 "children":[ 13 { 14 "id":55 15 } 16 ] 17 }, 18 { 19 "id":6 20 } 21 ] 22 } 23 ] 24}

上記のJSONをパースして出来るdicttree を引数として与え、最も浅いところの葉のdepthと、そのdepthの深さにある(複数存在する可能性のある)葉の中で最初にみつけたもののidを持つdict
(たとえば、 {'id': 8, 'depth': 1} )
を返す関数として、min_depth_func(tree)を作成しました。

Python3

1def min_depth_func(tree): 2 min_depth_node = {'id': -1, 'depth': None} 3 4 def update_min_depth_node_recursively(node, depth=0): 5 nonlocal min_depth_node 6 7 min_depth = min_depth_node['depth'] 8 if 'children' not in node: 9 if min_depth is None or depth < min_depth: 10 min_depth_node = {'id': node['id'], 'depth': depth} 11 else: 12 if min_depth is None or depth + 1 <= min_depth: 13 for child in node['children']: 14 update_min_depth_node_recursively(child, depth + 1) 15 16 update_min_depth_node_recursively(tree) 17 18 return min_depth_node 19

子ノードを左から調べていき、min_depth_nodeを更新します。最も浅い葉を特定するのが目的なので、min_depth_node['depth'] より深い位置へは降りていかないようにしています。

以下は、5個のテストツリーで、上記のmin_depth_func(tree) を試すコードです。

Python3

1if __name__ == '__main__': 2 import json 3 4 # test_1: min_width=1 (id: 8) 5 test_1 = '''{ 6 "id":1, 7 "children":[ 8 { 9 "id":8 10 }, 11 { 12 "id":5, 13 "children":[ 14 { 15 "id":11, 16 "children":[ 17 { 18 "id":55 19 } 20 ] 21 }, 22 { 23 "id":6 24 } 25 ] 26 } 27 ] 28 }''' 29 30 # test_2: min_width=1 (id: 8) 31 test_2 = '''{ 32 "id":1, 33 "children":[ 34 { 35 "id":5, 36 "children":[ 37 { 38 "id":11, 39 "children":[ 40 { 41 "id":55 42 } 43 ] 44 }, 45 { 46 "id":6 47 } 48 ] 49 }, 50 { 51 "id":8 52 } 53 ] 54 }''' 55 56 # test_3: min_width=0 (id: 1) 57 test_3 = '''{ 58 "id":1 59 }''' 60 61 # test_4: min_width=2 (id: 5) 62 test_4 = '''{ 63 "id":1, 64 "children": [ 65 { "id": 2, "children": [ { "id": 5 } ] }, 66 { "id": 3, "children": [ { "id": 6 } ] }, 67 { "id": 4, "children": [ { "id": 7 } ] } 68 ] 69 }''' 70 71 # test_5: min_width=1 (id: 8) 72 test_5 = '''{ 73 "id":1, 74 "children": [ 75 { "id": 2, "children": [ { "id": 5 } ] }, 76 { "id": 3, "children": [ { "id": 6 } ] }, 77 { "id": 4, "children": [ { "id": 7 } ] }, 78 { "id": 8 } 79 ] 80 }''' 81 82 for i, test_json in enumerate([test_1, test_2, test_3, test_4, test_5]): 83 tree_root = json.loads(test_json) 84 result = min_depth_func(tree_root) 85 print(f'test_{i+1}: min_depth_node={result}') 86

出力結果:

test_1: min_depth_node={'id': 8, 'depth': 1}

test_2: min_depth_node={'id': 8, 'depth': 1}
test_3: min_depth_node={'id': 1, 'depth': 0}
test_4: min_depth_node={'id': 5, 'depth': 2}
test_5: min_depth_node={'id': 8, 'depth': 1}

**動作確認用サンプル: ** ???? tera: 371423@replit.com/@kilesa

備考: ツリーのノードがどのようなデータ構造であるせよ、再帰による探索中に、不必要に深いところまで調べないで済むようなロジックを入れられるといいですね。

投稿2021/11/29 07:08

編集2021/11/29 07:56
退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

aya0425

2021/11/29 13:43

ご回答いただきありがとうございます。 詳細にご説明いただいたお陰で今回の概念の理解がとても深まりました。 ひとまず、実装したいこともあり、今回のベストアンサーには元のコードを活用した他の方を選ばせていただきましたが大変助かりました!
guest

0

ベストアンサー

以下のような感じでどうでしょうか?

python

1class Tree: 2 def __init__(self, val): 3 self.val = val 4 self.children = [] 5 6 def num_children(self): 7 return len(self.children) 8 9 10def min_depth_func(tree): 11 if tree.num_children() == 0: 12 return 1 13 14 depth_lst = [] 15 for kid in tree.children: 16 depth_lst.append(min_depth_func(kid)) 17 return 1 + min(depth_lst) 18 19 20A = Tree(1) 21B = Tree(8) 22C = Tree(5) 23D = Tree(11) 24E = Tree(6) 25F = Tree(5) 26A.children.append(B) 27A.children.append(C) 28C.children.append(D) 29C.children.append(E) 30D.children.append(F) 31ans = min_depth_func(A) - 1 # 根は0としてカウントするようなので、-1する 32print(ans) 33 34A = Tree(1) 35B = Tree(2) 36C = Tree(3) 37D = Tree(4) 38E = Tree(5) 39F = Tree(6) 40A.children.append(B) 41B.children.append(C) 42C.children.append(D) 43D.children.append(E) 44E.children.append(F) 45ans = min_depth_func(A) - 1 46print(ans)

投稿2021/11/29 06:06

退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

aya0425

2021/11/29 13:35

ご回答いただきありがとうございます。 ご提示いただいたコードの if tree.num_children() == 0: return 1 のreturnを0にしたところ望んでいた結果を得られました。 コード内容もしっかり理解できました。大変助かりました!
guest

0

全体的にうまくコード化できていません。
以下の概念コードを参考にしてみてください。

Python

1def min_depth_func(tree, 現在の階層位置): 2 if tree.num_children() == 0: 3 return 現在の階層位置 4 5 for kid in tree.children: 6 子供の結果 = min_depth_func(kid, 現在の階層位置+1) 7 8 return min(子供たちの結果)

投稿2021/11/29 02:48

can110

総合スコア38262

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

aya0425

2021/11/29 03:47

ご回答いただきありがとうございます。 追記で恐縮ですが、引数はtreeのみとのことです。 私の力不足で申し訳ないのですが、より詳細なご回答をいただけると大変嬉しいです。
can110

2021/11/29 04:03

ツリーノード自身が階層位置に関する情報を持っていれば引数で指定する必要はありません。 また、現状の再帰(深さ優先)処理ではなく幅優先で処理すれば同じく引数はtreeのみで実現できます。 課題のようなので、あとはご自身で頑張ってみてください。
aya0425

2021/11/29 13:47

追加のご回答ありがとうございます。ご指摘いただいた内容を踏まえて理解を深めていけるよう努力します。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問