This commit is contained in:
krahets
2026-03-30 08:17:41 +08:00
parent 68cafe99dd
commit 46bccf0065
484 changed files with 60193 additions and 20315 deletions
+63 -63
View File
@@ -6,7 +6,7 @@
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta name="description" content="アニメーション図解ワンクリック実行データ構造とアルゴリズムチュートリアル">
<meta name="description" content="アニメーション図解ワンクリック実行コードで学べるデータ構造とアルゴリズムの入門書">
<meta name="author" content="krahets">
@@ -117,7 +117,7 @@
<path
d="M480 32c0-12.9-7.8-24.6-19.8-29.6s-25.7-2.2-34.9 6.9L381.7 53c-48 48-113.1 75-181 75H192 160 64c-35.3 0-64 28.7-64 64v96c0 35.3 28.7 64 64 64l0 128c0 17.7 14.3 32 32 32h64c17.7 0 32-14.3 32-32V352l8.7 0c67.9 0 133 27 181 75l43.6 43.6c9.2 9.2 22.9 11.9 34.9 6.9s19.8-16.6 19.8-29.6V300.4c18.6-8.8 32-32.5 32-60.4s-13.4-51.6-32-60.4V32zm-64 76.7V240 371.3C357.2 317.8 280.5 288 200.7 288H192V192h8.7c79.8 0 156.5-29.8 215.3-83.3z" />
</svg>
<span>日本語版審閱者を募集しています!詳細<a href="https://github.com/krahets/hello-algo/blob/main/ja/CONTRIBUTING.md">CONTRIBUTING.md</a>参照してください。</span>
<span>日本語版のレビュアーを募集しています。詳しく<a href="/ja/chapter_appendix/contribution/">こちら</a>ご覧ください。</span>
</div>
</div>
@@ -341,7 +341,7 @@
<span class="md-ellipsis">
はじめに
@@ -358,7 +358,7 @@
<span class="md-nav__icon md-icon"></span>
はじめに
</label>
@@ -618,7 +618,7 @@
<span class="md-ellipsis">
1.1 &nbsp; アルゴリズムはどこにでもある
1.1 &nbsp; アルゴリズムは至るところにある
@@ -646,7 +646,7 @@
<span class="md-ellipsis">
1.2 &nbsp; アルゴリズムとは何か
1.2 &nbsp; アルゴリズムとは
@@ -783,7 +783,7 @@
<span class="md-ellipsis">
2.1 &nbsp; アルゴリズム効率評価
2.1 &nbsp; アルゴリズム効率評価
@@ -1060,7 +1060,7 @@
<span class="md-ellipsis">
3.3 &nbsp; 数値の符号化 *
3.3 &nbsp; 数値エンコーディング *
@@ -1088,7 +1088,7 @@
<span class="md-ellipsis">
3.4 &nbsp; 文字の符号化 *
3.4 &nbsp; 文字エンコーディング *
@@ -1591,7 +1591,7 @@
<span class="md-ellipsis">
第 6 章 &nbsp; ハッシュ
第 6 章 &nbsp; ハッシュテーブル
@@ -1613,7 +1613,7 @@
<span class="md-nav__icon md-icon"></span>
第 6 章 &nbsp; ハッシュ
第 6 章 &nbsp; ハッシュテーブル
</label>
@@ -1635,7 +1635,7 @@
<span class="md-ellipsis">
6.1 &nbsp; ハッシュ
6.1 &nbsp; ハッシュテーブル
@@ -1944,7 +1944,7 @@
<span class="md-ellipsis">
7.5 &nbsp; AVL木 *
7.5 &nbsp; AVL 木 *
@@ -2029,7 +2029,7 @@
<a href="#1" class="md-nav__link">
<span class="md-ellipsis">
1. &nbsp; 重要なポイント
1. &nbsp; 要点の振り返り
</span>
</a>
@@ -2177,7 +2177,7 @@
<span class="md-ellipsis">
8.2 &nbsp; ヒープ構築操作
8.2 &nbsp; ヒープ構築
@@ -2563,7 +2563,7 @@
<span class="md-ellipsis">
10.2 &nbsp; 二分探索の挿入
10.2 &nbsp; 二分探索の挿入位置
@@ -2619,7 +2619,7 @@
<span class="md-ellipsis">
10.4 &nbsp; ハッシュ最適化戦略
10.4 &nbsp; ハッシュによる最適化戦略
@@ -2647,7 +2647,7 @@
<span class="md-ellipsis">
10.5 &nbsp; 探索アルゴリズムの再認識
10.5 &nbsp; 探索アルゴリズム再考
@@ -3185,7 +3185,7 @@
<span class="md-ellipsis">
12.1 &nbsp; 分割統治アルゴリズム
12.1 &nbsp; 分割統治
@@ -3241,7 +3241,7 @@
<span class="md-ellipsis">
12.3 &nbsp; 木の構築問題
12.3 &nbsp; 二分木の構築問題
@@ -3269,7 +3269,7 @@
<span class="md-ellipsis">
12.4 &nbsp; ハノイの塔問題
12.4 &nbsp; ハノイの塔問題
@@ -3462,7 +3462,7 @@
<span class="md-ellipsis">
13.3 &nbsp; 部分集合和問題
13.3 &nbsp; 部分和問題
@@ -3490,7 +3490,7 @@
<span class="md-ellipsis">
13.4 &nbsp; Nクイーン問題
13.4 &nbsp; n クイーン問題
@@ -3631,7 +3631,7 @@
<span class="md-ellipsis">
14.1 &nbsp; 動的計画法の初歩
14.1 &nbsp; 動的計画法入門
@@ -3659,7 +3659,7 @@
<span class="md-ellipsis">
14.2 &nbsp; DP 問題特性
14.2 &nbsp; 動的計画法の問題特性
@@ -3687,7 +3687,7 @@
<span class="md-ellipsis">
14.3 &nbsp; DP の解法の考え方
14.3 &nbsp; 動的計画法の問題解決の考え方
@@ -3715,7 +3715,7 @@
<span class="md-ellipsis">
14.4 &nbsp; 0-1ナップサック問題
14.4 &nbsp; 0-1 ナップサック問題
@@ -3908,7 +3908,7 @@
<span class="md-ellipsis">
15.1 &nbsp; 貪欲アルゴリズム
15.1 &nbsp; 貪欲
@@ -4153,7 +4153,7 @@
<span class="md-ellipsis">
16.2 &nbsp; 一緒に作に参加する
16.2 &nbsp; 一緒に作に参加しましょう
@@ -4299,7 +4299,7 @@
<a href="#1" class="md-nav__link">
<span class="md-ellipsis">
1. &nbsp; 重要なポイント
1. &nbsp; 要点の振り返り
</span>
</a>
@@ -4355,42 +4355,42 @@
<!-- Page content -->
<h1 id="76">7.6 &nbsp; まとめ<a class="headerlink" href="#76" title="Permanent link">&para;</a></h1>
<h3 id="1">1. &nbsp; 重要なポイント<a class="headerlink" href="#1" title="Permanent link">&para;</a></h3>
<h3 id="1">1. &nbsp; 要点の振り返り<a class="headerlink" href="#1" title="Permanent link">&para;</a></h3>
<ul>
<li>二分木は非線形データ構造で、「一つを二つに分ける」分割統治のロジックを反映しています。各二分木ノードには値と2つのポインタが含まれ、それぞれ左と右子ノードを指します。</li>
<li>二分木のノードについて、その左(右)子ノードとその下に形成される木は、まとめてそのノードの左(右)部分木と呼ばれます</li>
<li>二分木に関する用語には、根ノード、葉ノード、レベル、次数、エッジ、高さ、深さがあります</li>
<li>二分木の初期化、ノードの挿入、ノードの削除の操作は、連結リストの操作と似ています</li>
<li>一般的な二分木の種類には、完全二分木、完備二分木、満二分木、平衡二分木があります。完全二分木は理想的な状態を表し、連結リストは退化後の最悪の状態で</li>
<li>二分木は、ノード値と空きスロットをレベル順走査シーケンスで配置し、親ノードと子ノードのインデックスマッピング関係に基づいてポインタを実することで、配列を使用して表現できます</li>
<li>二分木のレベル順走査は幅優先探索手法で、「円を拡大しながら」の層ごとの走査方式を反映しています。通常はキューを使用して実装されます</li>
<li>前順、中順、後順走査はすべて深度優先探索手法で、「まず最後まで行き、その後バックトラックして続行する」走査方式を反映しています。通常は再帰を使用して実装されます</li>
<li>二分探索木は要素検索のための効率的なデータ構造で、検索、挿入、削除操作の時間計算量はすべて<span class="arithmatex">\(O(\log n)\)</span>です。二分探索木が連結リスト退化すると、これらの時間計算量は<span class="arithmatex">\(O(n)\)</span>に悪化します</li>
<li>AVL木は平衡二分探索木とも呼ばれ、回転操作を通して継続的なノード挿入と削除後も木が平衡を保つことを保証します</li>
<li>AVL木の回転操作には、右回転、左回転、右左回転、左右回転があります。ノードの挿入または削除後、AVL木はボトムアップ方式でこれらの回転を実行して自己平衡を取ります。</li>
<li>二分木は非線形データ構造の一種であり、「二分する」分割統治の考え方を体現してい。各二分木ノードは 1 つの値と 2 本のポインタを持ち、それぞれ左子ノードと右子ノードを指す。</li>
<li>二分木のあるノードについて、その左(右)子ノードおよびその配下から構成される木を、そのノードの左(右)部分木と呼</li>
<li>二分木に関する用語には、根ノード、葉ノード、レベル、次数、、高さ、深さなどがある</li>
<li>二分木の初期化、ノードの挿入、ノードの削除は、連結リストの操作方法と似てい</li>
<li>一般的な二分木の種類には、perfect 二分木、complete 二分木、full 二分木、平衡二分木がある。perfect 二分木が最も理想的な状態であり、連結リストは退化後の最悪の状態である</li>
<li>二分木は配列で表現できる。方法としては、ノード値と空き位置をレベル順走査の順に並べ、親ノードと子ノードのインデックス対応関係に基づいてポインタを実する。</li>
<li>二分木のレベル順走査は幅優先探索の一種であり、「同心円状に外へ広がる」ような逐次的な走査方式を表しており、通常はキューによって実装され</li>
<li>前順、中順、後順走査はいずれも深さ優先探索に属し、「まず末端まで進み、その後バックトラックして続ける」という走査方式を体現しており、通常は再帰で実装され</li>
<li>二分探索木は効率的な要素探索データ構造であり、探索、挿入、削除の時間計算量はいずれも <span class="arithmatex">\(O(\log n)\)</span> である。二分探索木が連結リスト退化すると、各操作の時間計算量は <span class="arithmatex">\(O(n)\)</span> まで悪化する</li>
<li>AVL 木は平衡二分探索木とも呼ばれ、回転操作によって、ノード挿入と削除を繰り返した後も木が平衡を保つようにしている</li>
<li>AVL 木の回転操作には、右回転、左回転、右回転してから左回転、左回転してから右回転があ。ノードの挿入または削除後、AVL 木は下から上へ回転操作を行い、木を再び平衡状態に戻す。</li>
</ul>
<h3 id="2-q-a">2. &nbsp; Q &amp; A<a class="headerlink" href="#2-q-a" title="Permanent link">&para;</a></h3>
<p><strong>Q</strong>: 一つのノードのみを持つ二分木について、木の高さと根ノードの深さの両方が<span class="arithmatex">\(0\)</span>ですか?</p>
<p>はい高さと深さは通常「通過したエッジの数」として定義されるためです。</p>
<p><strong>Q</strong>: 二分木における挿入と削除は一般的に一連の操作によって達成されます。ここで「一連の操作」とは何を指しますか?子ノードのリソース解放することを意味しますか?</p>
<p>二分探索木を例にると、ノード削除する操作は3つの異なるシナリオで処理する必要があり、それぞれ複数ステップのノード操作が必要す。</p>
<p><strong>Q</strong>: 二分木のDFS走査で前順中順後順の3つのシーケンスがあるのはなぜですか?その用途は何ですか?</p>
<p>配列の順次および逆順走査と同様に、前順中順後順走査は二分木を走査する3つの方法であり、特定の順序で走査結果を取得できます。えば二分探索木では、ノードサイズが「左子ノード値 &lt; 根ノード値 &lt; 右子ノード値」を満たすため、「左 <span class="arithmatex">\(\rightarrow\)</span><span class="arithmatex">\(\rightarrow\)</span> 右」の優先順で木を走査することで、順序付けられたノードシーケンスを取得できます。</p>
<p><strong>Q</strong>: 不平衡ノード<code>node</code><code>child</code><code>grand_child</code>の関係を処理する右回転操作において、右回転後に<code>node</code>とその親ノード間の接続<code>node</code>の元のリンクが失われるのではありませんか?</p>
<p>この問題再帰的な観点からる必要があります。<code>right_rotate(root)</code>操作は部分木の根ノードを渡し、最終的に<code>return child</code>で回転された部分木の根ノードを返します。部分木の根ノードとその親ノードの接続は、この関数が戻った後に確立され、これは右回転操作の保守範囲外です</p>
<p><strong>Q</strong>: C++では関数<code>private</code><code>public</code>セクションに分かれています。これにはどのような考慮事項がありますか?なぜ<code>height()</code>関数と<code>updateHeight()</code>関数それぞれ<code>public</code><code>private</code>に配置されているのですか?</p>
<p>これはメソッドの使用範囲によります。メソッドがクラス内でのみ使用される場合<code>private</code>に設計されます。えば、ユーザーが独自に<code>updateHeight()</code>を呼び出すことは意味がありません。これは挿入または削除操作の一ステップに過ぎないからです。しかし、<code>height()</code>はノードの高さにアクセスするためのもので、<code>vector.size()</code>と同様であるため、使用のために<code>public</code>に設定されています。</p>
<p><strong>Q</strong>: 入力データのセットから二分探索木をどのように構築しますか?根ノードの選択は非常に重要ですか?</p>
<p>はい、木を構築する方法は二分探索木コード<code>build_tree()</code>メソッドで提供されています。根ノードの選択については、通常入力データをソートし、中央の要素を根ノードして選択し、再帰的に左と右の部分木を構築します。このアプローチは木の平衡を最大化します。</p>
<p><strong>Q</strong>: Javaでは、文字列比較に常に<code>equals()</code>メソッドを使用する必要がありますか?</p>
<p>Javaでは、プリミティブデータ型の場合、<code>==</code>は2つの変数の値が等しいかどうかを比較するために使用されます。参照型の場合、2つのシンボルの動作原理は異なります。</p>
<p><strong>Q</strong>:ノードが 1 つしかない二分木では、木の高さと根ノードの深さはどちらも <span class="arithmatex">\(0\)</span> ですか?</p>
<p>はい高さと深さは通常「通過した辺の本数」として定義されるからです。</p>
<p><strong>Q</strong>二分木における挿入と削除は通常一連の操作を組み合わせて完了しますが、ここでいう「一連の操作」とは何を指すのでしょうか?リソースの子ノードに対するリソース解放と理解できますか?</p>
<p>二分探索木を例にると、ノード削除は 3 つのケースに分けて処理する必要があり、各ケースで複数段階のノード操作が必要になります。</p>
<p><strong>Q</strong>:なぜ DFS による二分木走査には前順中順後順の 3 種類があり、それぞれどのような用途があるのですか?</p>
<p>配列の順方向走査と逆方向走査に似て、前順中順後順走査は二分木の 3 つの走査方法であり、特定の順序で走査結果を得るために使えます。たとえば二分探索木では、ノードの大小関係が <code>左子ノード&lt; 根ノード&lt; 右子ノードの値</code> を満たすため、「左 <span class="arithmatex">\(\rightarrow\)</span><span class="arithmatex">\(\rightarrow\)</span> 右」の優先順で木を走査すれば、整列済みのノード列を得られます。</p>
<p><strong>Q</strong>:右回転操作は不平衡ノード <code>node</code><code>child</code><code>grand_child</code> の関係を処理するものですが、<code>node</code> の親ノードと <code>node</code> の元の接続は維持しなくてよいのですか?右回転後に切れてしまいませんか?</p>
<p>この問題再帰の視点から考える必要があります。右回転操作 <code>right_rotate(root)</code> に渡されるのは部分木の根ノードであり、最終的に <code>return child</code> によって回転後の部分木の根ノードを返します。部分木の根ノードとその親ノードの接続は、この関数の返却後に行われるため、右回転操作自身が管理する範囲には含まれません</p>
<p><strong>Q</strong>C++ では関数<code>private</code><code>public</code> に分けますが、この設計にはどのような考がありますか?なぜ <code>height()</code> 関数と <code>updateHeight()</code> 関数それぞれ <code>public</code><code>private</code> に置くのですか?</p>
<p>主に、そのメソッドの用範囲を見て決めます。メソッドがクラス内部でしか使われないなら<code>private</code> に設計ます。たとえば、利用者が <code>updateHeight()</code> を単独で呼び出しても意味はなく、これは挿入や削除の途中の 1 ステップにすぎません。一方で <code>height()</code> はノードの高さにアクセスするためのもので、<code>vector.size()</code> に似た役割を持つため、使いやすいように <code>public</code> に設定ます。</p>
<p><strong>Q</strong>入力データの集合から二分探索木をどのように構築しますか?根ノードの選び方は重要ですか?</p>
<p>はい。木の構築方法は二分探索木コード中の <code>build_tree()</code> メソッドですでに示されています。根ノードの選択については、通常入力データをソートし、その中央の要素を根ノードしてから、左右の部分木を再帰的に構築します。こうすることで、木の平衡を最大限に保てます。</p>
<p><strong>Q</strong>Java では、文字列比較には必ず <code>equals()</code> メソッドを使うべきですか?</p>
<p>Java では、基本データ型については <code>==</code> を使って 2 つの変数の値が等しいかどうかを比較します。参照型については、この 2 つの記法の働き方は異なります。</p>
<ul>
<li><code>==</code>: 2つの変数が同じオブジェクトを指しているかどうか、つまりメモリの位置が同じかどうかを比較するために使用されます。</li>
<li><code>equals()</code>: 2つのオブジェクトの値が等しいかどうかを比較するために使用されます。</li>
<li><code>==</code> 2 つの変数が同じオブジェクトを指しているか、つまりメモリの位置が同じかどうかを比較するために使ます。</li>
<li><code>equals()</code>2 つのオブジェクトの値が等しいかどうかを比較するために使ます。</li>
</ul>
<p>したがって、値を比較するには<code>equals()</code>を使用すべきです。ただし、<code>String a = "hi"; String b = "hi";</code>初期化された文字列は文字列定数プールに格納され、同じオブジェクトを指すため、<code>a == b</code>も2つの文字列の内容を比較するために使用できます。</p>
<p><strong>Q</strong>: 最下位レベルに到達する前に、幅優先走査でキュー内のノード数は<span class="arithmatex">\(2^h\)</span>ですか?</p>
<p>はい、例えば高さ<span class="arithmatex">\(h = 2\)</span>の満二分木は合計<span class="arithmatex">\(n = 7\)</span>個のノードを持ち、最下位レベルには<span class="arithmatex">\(4 = 2^h = (n + 1) / 2\)</span>個のノードがあります。</p>
<p>したがって、値を比較したい場合は <code>equals()</code> を使べきです。ただし、<code>String a = "hi"; String b = "hi";</code> によって初期化された文字列は文字列定数プールに格納され、同じオブジェクトを指すため、<code>a == b</code> でも 2 つの文字列の内容を比較できます。</p>
<p><strong>Q</strong>:幅優先走査で最下層に到達する前、キュー内のノード数は <span class="arithmatex">\(2^h\)</span> ですか?</p>
<p>はい。たとえば高さ <span class="arithmatex">\(h = 2\)</span> の充足二分木では、ノード総数は <span class="arithmatex">\(n = 7\)</span> であり、最下層のノード数は <span class="arithmatex">\(4 = 2^h = (n + 1) / 2\)</span>す。</p>
<!-- Source file information -->
@@ -4413,7 +4413,7 @@ aria-label="フッター"
<a
href="../avl_tree/"
class="md-footer__link md-footer__link--prev"
aria-label="前: 7.5 &amp;nbsp; AVL木 *"
aria-label="前: 7.5 &amp;nbsp; AVL 木 *"
rel="prev"
>
<div class="md-footer__button md-icon">
@@ -4425,7 +4425,7 @@ aria-label="フッター"
</span>
<div class="md-ellipsis">
7.5 &nbsp; AVL木 *
7.5 &nbsp; AVL 木 *
</div>
</div>
</a>