mirror of
https://github.com/krahets/hello-algo.git
synced 2026-11-02 03:05:24 +08:00
* Retranslate the complete Japanese online edition from Chinese * Fit Japanese homepage labels and localize heading permalinks * Point Japanese contribution instructions to the Japanese preview * Replace locale conditionals with multilingual UI tables
55 lines
5.3 KiB
Markdown
55 lines
5.3 KiB
Markdown
# まとめ
|
||
|
||
### 要点の振り返り
|
||
|
||
- 二分木は「一つを二つに分ける」という分割統治の論理を表す非線形データ構造です。各ノードには値と、左右の子をそれぞれ指す二つのポインタがあります。
|
||
- あるノードの左(右)の子とその下のノードが作る木を、そのノードの左(右)部分木と呼びます。
|
||
- 関連する用語には、根ノード、葉ノード、レベル、次数、辺、高さ、深さなどがあります。
|
||
- 初期化、ノードの挿入・削除の方法は、連結リストと似ています。
|
||
- 主な種類には、パーフェクト二分木、完全二分木、全二分木、平衡二分木があります。パーフェクト二分木は最も理想的な状態で、連結リストは退化した最悪の状態です。
|
||
- 二分木は配列でも表せます。ノードの値と空の位置をレベル順に並べ、親子のインデックスの対応でポインタを実現します。
|
||
- レベル順走査は幅優先探索の一種で、一周ずつ外へ広がるように層ごとに進み、通常はキューで実装します。
|
||
- 行きがけ順、通りがけ順、帰りがけ順は深さ優先探索で、行き止まりまで進んでから戻って続ける方法です。通常は再帰で実装します。
|
||
- 二分探索木は要素を効率よく探せるデータ構造で、探索、挿入、削除の時間計算量はすべて $O(\log n)$ です。連結リストに退化すると、いずれも $O(n)$ に悪化します。
|
||
- AVL 木は平衡二分探索木とも呼ばれ、回転によって、挿入と削除を続けても平衡を保ちます。
|
||
- AVL 木の回転には、右回転、左回転、右回転してから左回転、左回転してから右回転があります。挿入や削除の後、下から上へ回転して平衡を取り戻します。
|
||
|
||
### Q & A
|
||
|
||
**Q**:ノードが一つだけの二分木では、木の高さも根の深さも $0$ ですか?
|
||
|
||
はい。通常は、通る辺の数で高さと深さを定義するためです。
|
||
|
||
**Q**:二分木の挿入・削除は複数の操作を組み合わせるとありますが、どういう意味ですか? リソースの子ノードのリソースを解放することと考えてよいですか?
|
||
|
||
二分探索木を例にすると、削除には三つの場合があり、それぞれで複数のノード操作が必要です。
|
||
|
||
**Q**:二分木の DFS には、なぜ行きがけ順、通りがけ順、帰りがけ順があり、それぞれ何に使いますか?
|
||
|
||
配列を順方向や逆方向に走査するのと同様、これらは特定の順序で結果を得るための三つの走査方法です。例えば二分探索木では、`左の子の値 < 根の値 < 右の子の値` が成り立つため、「左 $\rightarrow$ 根 $\rightarrow$ 右」の順で走査すれば、整列済みのノード列を得られます。
|
||
|
||
**Q**:右回転は不均衡な `node`、`child`、`grand_child` の関係を処理しますが、`node` と親のつながりは更新しなくてよいのですか? 切れてしまいませんか?
|
||
|
||
再帰の視点から考える必要があります。`right_rotate(root)` は部分木の根を受け取り、最後に `return child` で回転後の根を返します。部分木の根と親の接続は、この関数から戻った後に行うので、右回転の処理範囲には含まれません。
|
||
|
||
**Q**:C++ で関数を `private` と `public` に分ける基準は何ですか? `height()` は `public`、`updateHeight()` は `private` なのはなぜですか?
|
||
|
||
主に利用範囲で決めます。クラス内部だけで使うなら `private` にします。例えば `updateHeight()` は挿入や削除の一段階なので、利用者が単独で呼ぶ意味はありません。一方、`height()` は `vector.size()` のように高さを取得するものなので、使えるように `public` にします。
|
||
|
||
**Q**:入力データから二分探索木をどう構築しますか? 根の選び方は重要ですか?
|
||
|
||
はい。構築方法は、二分探索木のコードの `build_tree()` にあります。通常、入力をソートして中点の要素を根とし、左右の部分木を再帰的に構築します。こうすることで、平衡性をできるだけ高く保てます。
|
||
|
||
**Q**:Java の文字列比較には、必ず `equals()` を使いますか?
|
||
|
||
Java では、基本データ型の `==` は二つの変数の値が等しいかを比較します。参照型では、二つの方法の仕組みが異なります。
|
||
|
||
- `==`:二つの変数が同じオブジェクト、つまり同じメモリ位置を指すかを比較します。
|
||
- `equals()`:二つのオブジェクトの値が等しいかを比較します。
|
||
|
||
値を比較するなら `equals()` を使うべきです。ただし、`String a = "hi"; String b = "hi";` で初期化した文字列は文字列定数プールに格納され、同じオブジェクトを指すため、`a == b` でも内容を比較できます。
|
||
|
||
**Q**:幅優先走査で最下層に到達する直前、キューのノード数は $2^h$ ですか?
|
||
|
||
はい。例えば高さ $h = 2$ のパーフェクト二分木なら、総ノード数は $n = 7$ で、最下層のノード数は $4 = 2^h = (n + 1) / 2$ です。
|