Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Maximum Depth of Binary Tree #41

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open

Conversation

type entry struct {
node *TreeNode
depth int
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

慣例として構造体は使用箇所より前で定義すると思います

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

慣例かは知らないですが、確かに最初に定義するのが一般的ですね

if root == nil {
return 0
}
maximum := 0

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

max_depth

if e.node == nil {
continue
}
maximum = max(maximum, e.depth)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maximum = e.depth

return 0
}
maximum := 0
stack := []entry{{root, 1}}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

データ構造を変数名にするのはあまり良くないと思いました

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

私は、比較的、stack や queue という名前は状況次第で許容側です。
何が入っているかが分かって、その後でどのように使われるか(後ろで出し入れする)のヒントになっています。
そうすると、その後を読む流れをあまり阻害しないからです。
ただ、どういう物が入っているか、説明するのが複雑であるならば、何が入っている stack なのか説明が欲しくなります。

一方で、関数名はだいたい詳細に説明して欲しいです。たとえば、dfs() とだけあると、何が返ってくるかが分からないので、dfs の中を読みにいかないといけなくなります。

@hroc135
Copy link

hroc135 commented Sep 30, 2024

多くの解法を試していて参考になりました
最終的にどの解法が最適だと思われましたか?

#15 (comment) の議論だと再帰はあまり望ましくないとありましたが、入力サイズが小さいので再帰でやってしまうか、それ以外だとmaxDepthIterativeDFSになるのかなと思いました

queue := []entry{{root, 1}}
for len(queue) > 0 {
e := queue[0]
queue = queue[1:]
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

自分は Go 言語に詳しくないため質問させていただきたいのですが、このように書いた場合、配列の後半のコピーが作成されるのでしょうか?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

インデックス1以降の要素が含まれた動的配列が代入されます。
https://go.dev/ref/spec#Slice_expressions

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

コピーは作られず、 インデックスとポインタの対応関係が変わるような動作になります。

Slicing does not copy the slice’s data. It creates a new slice value that points to the original array. This makes slice operations as efficient as manipulating array indices. Therefore, modifying the elements (not the slice itself) of a re-slice modifies the elements of the original slice:

d := []byte{'r', 'o', 'a', 'd'}
e := d[2:]
// e == []byte{'a', 'd'}
e[1] = 'm'
// e == []byte{'a', 'm'}
// d == []byte{'r', 'o', 'a', 'm'}

https://go.dev/blog/slices-intro

一番オーソドックスなやり方。

1フレームの大きさは、引数8 + 返り値8 + ローカル変数(8 + 8) + FP + 戻りアドレス = 48Bぐらい。最大ノード数が10^4なのでスタックサイズは、48 * 10^4 = 480KBぐらいになると予想できる。
Linuxのデフォルトのスタックの大きさが8MBなのでスタックオーバーフローの危険性は低い。
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

自分ここら辺の理解が浅いので質問させてください!
ここでLinuxのスタックサイズを考慮するのはなぜですか?

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Goはランタイムがよしなにやってくれているだけで、OSスレッド上でプログラムが動作していることには変わりがないので、、

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

前に教えていただいたGoのスタックサイズの上限をこの時は知らず、調べても出てこなかったので、とりあえずはLinuxのスレッドに割り当てられるスタックのデフォルトサイズを基準に考えたという感じですね

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GoがLinuxのスタックサイズを超えてスタックを割り当てられるのは、Goランタイムが適宜ヒープからメモリ領域を割り当てて、スタックサイズを拡張している感じだった気がします(今パッとソースが出てこないのですが、確かそうだったはず)

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ありがとうございます。勉強になります!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants