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
@@ -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; アルゴリズムとは
@@ -785,7 +785,7 @@
<span class="md-ellipsis">
2.1 &nbsp; アルゴリズム効率評価
2.1 &nbsp; アルゴリズム効率評価
@@ -954,7 +954,7 @@
<a href="#1" class="md-nav__link">
<span class="md-ellipsis">
1. &nbsp; 重要なレビュー
1. &nbsp; 要点の振り返り
</span>
</a>
@@ -1132,7 +1132,7 @@
<span class="md-ellipsis">
3.3 &nbsp; 数値の符号化 *
3.3 &nbsp; 数値エンコーディング *
@@ -1160,7 +1160,7 @@
<span class="md-ellipsis">
3.4 &nbsp; 文字の符号化 *
3.4 &nbsp; 文字エンコーディング *
@@ -1663,7 +1663,7 @@
<span class="md-ellipsis">
第 6 章 &nbsp; ハッシュ
第 6 章 &nbsp; ハッシュテーブル
@@ -1685,7 +1685,7 @@
<span class="md-nav__icon md-icon"></span>
第 6 章 &nbsp; ハッシュ
第 6 章 &nbsp; ハッシュテーブル
</label>
@@ -1707,7 +1707,7 @@
<span class="md-ellipsis">
6.1 &nbsp; ハッシュ
6.1 &nbsp; ハッシュテーブル
@@ -2014,7 +2014,7 @@
<span class="md-ellipsis">
7.5 &nbsp; AVL木 *
7.5 &nbsp; AVL 木 *
@@ -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,44 +4355,47 @@
<!-- Page content -->
<h1 id="25">2.5 &nbsp; まとめ<a class="headerlink" href="#25" title="Permanent link">&para;</a></h1>
<h3 id="1">1. &nbsp; 重要なレビュー<a class="headerlink" href="#1" title="Permanent link">&para;</a></h3>
<p><strong>アルゴリズム効率評価</strong></p>
<h3 id="1">1. &nbsp; 要点の振り返り<a class="headerlink" href="#1" title="Permanent link">&para;</a></h3>
<p><strong>アルゴリズム効率評価</strong></p>
<ul>
<li>時間効率と空間効率は、アルゴリズムの優劣を評価する2つの主要な基準です。</li>
<li>際のテストによってアルゴリズム効率を評価できますが、テスト環境の影響を排除することは困難で、大量の計算リソースを消費します。</li>
<li>複雑度分析は実際のテストの欠点を克服できます。その結果はすべての動作プラットフォームに適用でき、異なるデータスケールでのアルゴリズムの効率明らかにできます。</li>
<li>時間効率と空間効率は、アルゴリズムの良し悪しを測る二つの主要な評価指標です。</li>
<li>によってアルゴリズム効率を評価できますが、テスト環境の影響を排除しにくく、多くの計算資源も消費します。</li>
<li>複雑度分析は実測の欠点を補い、分析結果はすべての実行プラットフォームに適用でき、データ規模ごとの効率明らかにできます。</li>
</ul>
<p><strong>時間計算量</strong></p>
<ul>
<li>時間計算量は、データ量の増加に伴うアルゴリズムの実行時間の傾向を測定し、アルゴリズムの効率を効果的に評価します。しかし、入力データ量が少ない場合や時間計算量が同じ場合など、特定のケースでは失敗することがあり、アルゴリズムの効率を正確に比較することが困難になります。</li>
<li>最悪ケース時間計算量はビッグ<span class="arithmatex">\(O\)</span>記法を使用して表記され、漸近上限を表し、<span class="arithmatex">\(n\)</span>無限大に近づくにつれての操作数<span class="arithmatex">\(T(n)\)</span>の増加レベルを反映します。</li>
<li>時間計算量の計算には2つのステップが含まれます:まず操作数をカウントし、次に漸近上限を決定します。</li>
<li>一般的な時間計算量は、低いものから高いものへと並べると、<span class="arithmatex">\(O(1)\)</span><span class="arithmatex">\(O(\log n)\)</span><span class="arithmatex">\(O(n)\)</span><span class="arithmatex">\(O(n \log n)\)</span><span class="arithmatex">\(O(n^2)\)</span><span class="arithmatex">\(O(2^n)\)</span><span class="arithmatex">\(O(n!)\)</span>などが含まれます。</li>
<li>一部のアルゴリズムの時間計算量は固定されておらず、入力データの分布に依存します。時間計算量は最悪、最良、平均のケースに分けられます。最良ケースは、入力データが最良ケースを達成するために厳格な条件を満たす必要があるため、ほとんど使用されません。</li>
<li>平均時間計算量は、ランダムデータ入力下でのアルゴリズムの効率を反映し、実際のアプリケーションでのアルゴリズムの性能に密接に類似しています。平均時間計算量の計算には、入力データの分布とその後の数学的期待値を考慮する必要があります。</li>
<li>時間計算量は、アルゴリズムの実行時間がデータ量の増加に伴ってどう変化するかを測るためのものであり、効率評価に有効です。ただし、入力データ量が小さい場合や時間計算量が同じ場合などには、効率の優劣を正確に比較できないことがあります。</li>
<li>最悪時間計算量はビッグオー記法 <span class="arithmatex">\(O\)</span> で表され、関数の漸近上界に対応し、<span class="arithmatex">\(n\)</span> が正の無限大に近づくときの操作回数 <span class="arithmatex">\(T(n)\)</span> の増加の度合いを表します。</li>
<li>時間計算量の推定は二段階に分かれ、まず操作数を数え、次に漸近上界を判断します。</li>
<li>一般的な時間計算量を低い順から並べると、<span class="arithmatex">\(O(1)\)</span><span class="arithmatex">\(O(\log n)\)</span><span class="arithmatex">\(O(n)\)</span><span class="arithmatex">\(O(n \log n)\)</span><span class="arithmatex">\(O(n^2)\)</span><span class="arithmatex">\(O(2^n)\)</span><span class="arithmatex">\(O(n!)\)</span> などがあります。</li>
<li>一部のアルゴリズムの時間計算量は固定ではなく、入力データの分布に関係します。時間計算量は最悪、最良、平均時間計算量がありますが、最良時間計算量は入力データが厳しい条件を満たす必要があるため、ほとんど使れません。</li>
<li>平均時間計算量は、ランダムな入力データに対するアルゴリズムの実行効率をし、実運用時の性能に最も近い指標です。平均時間計算量を求めるには、入力データの分布と、それを踏まえた数学的期待値を統計する必要があります。</li>
</ul>
<p><strong>空間計算量</strong></p>
<ul>
<li>空間計算量は時間計算量と同様に、データ量の増加に伴うアルゴリズムが占有するメモリ空間の傾向を測定します。</li>
<li>アルゴリズム実行中に使用される関連メモリ空間は、入力空間、一時空間、出力空間に分けることができます。一般的に、入力空間は空間計算量の計算に含まれません。一時空間は一時データ、スタックフレーム空間、命令空間に分けることができ、スタックフレーム空間は通常、再帰関数でのみ空間計算量に影響します。</li>
<li>通常最悪ケース空間計算量のみに焦点を当てます。これは、最悪の入力データと操作の最悪の瞬間でのアルゴリズムの空間計算量を計算することを意味します。</li>
<li>一般的な空間計算量は、低いものから高いものへと並べると、<span class="arithmatex">\(O(1)\)</span><span class="arithmatex">\(O(\log n)\)</span><span class="arithmatex">\(O(n)\)</span><span class="arithmatex">\(O(n^2)\)</span><span class="arithmatex">\(O(2^n)\)</span>などが含まれます。</li>
<li>空間計算量の役割は時間計算量に似ており、アルゴリズムが使用するメモリ空間がデータ量の増加に伴ってどう変化するかを測ります。</li>
<li>アルゴリズム実行中に関係するメモリ空間は、入力空間、一時空間、出力空間に分けられます。通常、入力空間は空間計算量の計算に含ません。一時空間は一時データ、スタックフレーム空間、命令空間に分けられ、このうちスタックフレーム空間は通常、再帰関数でのみ空間計算量に影響します。</li>
<li>私たちは通常最悪空間計算量のみに注目し、最悪の入力データと最悪の実行時点における空間計算量を数えます。</li>
<li>一般的な空間計算量を低い順から並べると、<span class="arithmatex">\(O(1)\)</span><span class="arithmatex">\(O(\log n)\)</span><span class="arithmatex">\(O(n)\)</span><span class="arithmatex">\(O(n^2)\)</span><span class="arithmatex">\(O(2^n)\)</span> などがあります。</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">\(O(1)\)</span>ですか?</p>
<p>理論的には、末尾再帰関数の空間計算量は<span class="arithmatex">\(O(1)\)</span>最適化できます。しかし、ほとんどのプログラミング言語(Java、Python、C++、Go、C#など)は尾再帰の自動最適化をサポートしていないため、一般的に空間計算量<span class="arithmatex">\(O(n)\)</span>と考えられています。</p>
<p><strong>Q</strong>: 「関数」と「メソッドという用語の違いは何ですか?</p>
<p><u>関数</u>は独立して実行でき、すべてのパラメータが明示的に渡されます。<u>メソッド</u>はオブジェクトに関連付けられ、それを呼び出すオブジェクト暗黙的に渡され、クラスのインスタンスに含まれるデータを操作できます。</p>
<p>一般的なプログラミング言語からの例をいくつか示します</p>
<p><strong>Q</strong>尾再帰の空間計算量は <span class="arithmatex">\(O(1)\)</span> ですか?</p>
<p>理論上、尾再帰関数の空間計算量は <span class="arithmatex">\(O(1)\)</span> まで最適化できます。ただし、ほとんどのプログラミング言語(Java、Python、C++、Go、C# など)は尾再帰の自動最適化をサポートしていないため、通常は空間計算量<span class="arithmatex">\(O(n)\)</span> と見なします。</p>
<p><strong>Q</strong>:関数とメソッドという二つの用語の違いは何ですか?</p>
<p><u>関数function</u>は独立して実行でき、すべての引数は明示的に渡されます。<u>メソッドmethod</u>はオブジェクトに関連付けられ、それを呼び出すオブジェクト暗黙的に渡され、クラスのインスタンスに含まれるデータを操作できます。</p>
<p>以下では、いくつかの一般的なプログラミング言語を例に説明します</p>
<ul>
<li>Cは手続き型プログラミング言語で、オブジェクト指向の概念がないため、関数のみがあります。しかし、構造体(struct)を作成することでオブジェクト指向プログラミングをシミュレートでき、これらの構造体に関連付けられた関数は他のプログラミング言語のメソッドと同等です。</li>
<li>JavaC#はオブジェクト指向プログラミング言語で、コードブロック(メソッド)は通常クラスの一部です。静的メソッドはクラスにバインドされ、特定のインスタンス変数にアクセスできないため、関数のように動作します</li>
<li>C++Python手続き型プログラミング(関数)オブジェクト指向プログラミング(メソッド)の両方をサポートしています。</li>
<li>C 言語は手続き型プログラミング言語であり、オブジェクト指向の概念がないため、関数しかありません。ただし、構造体(struct)を作成してオブジェクト指向プログラミングを模倣でき、構造体に関連付けられた関数は他のプログラミング言語におけるメソッドに相当します。</li>
<li>JavaC# はオブジェクト指向プログラミング言語であり、コードブロック(メソッド)は通常あるクラスの一部です。静的メソッドの振る舞いは関数に似ており、クラスに束縛され、特定のインスタンス変数にアクセスできません</li>
<li>C++Python は、手続き型プログラミング(関数)にもオブジェクト指向プログラミング(メソッド)にも対応しています。</li>
</ul>
<p><strong>Q</strong>: 「空間計算量の一般的な種類」の図は、占有空間の絶対サイズを反映していますか?</p>
<p>いいえ、図は空間計算量を示しており、これは増加傾向を反映するものであり、占有空間の絶対サイズではありません。</p>
<p><span class="arithmatex">\(n = 8\)</span>を取ると、各曲線の値がその関数に対応していないことに気づくかもしれません。これは、各曲線に定数項が含まれているためで、値の範囲を視覚的に快適な範囲圧縮することを意図しています。</p>
<p>実際には、通常は各メソッドの「定数項」複雑度を知らないため、複雑度のみに基づいて<span class="arithmatex">\(n = 8\)</span>の最良ソリューションを選択することは一般的に不可能です。しかし、<span class="arithmatex">\(n = 8^5\)</span>の場合、増加傾向が支配的になるため、選択がはるかに容易になります。</p>
<p><strong>Q</strong>:「一般的な空間計算量の種類」の図が表しているのは、使用空間の絶対量ですか?</p>
<p>いいえ。この図が示しているのは空間計算量であり、表しているのは増加傾向であって、使用空間の絶対ではありません。</p>
<p><span class="arithmatex">\(n = 8\)</span> と仮定すると、各曲線の値が対応する関数と一致していないように見えるかもしれません。これは、各曲線に定数項が含まれており、値の範囲を視覚的に見やすい範囲圧縮しているためです。</p>
<p>実際には、各手法の「定数項」複雑度がどれほどか通常は分からないため、一般に複雑度だけを根拠に <span class="arithmatex">\(n = 8\)</span> 以下で最適解を選ぶことはできません。ただし、<span class="arithmatex">\(n = 8^5\)</span> であれば選びやすく、このときは増加傾向がすでに支配的になっています。</p>
<p><strong>Q</strong> 実際の利用場面に応じて、時間(または空間)を犠牲にしてアルゴリズムを設計することはありますか?</p>
<p>実際の応用では、多くの場合、空間を犠牲にして時間を得る選択をします。たとえばデータベースのインデックスでは、通常 B+ 木やハッシュインデックスを構築し、大量のメモリ空間を使う代わりに、<span class="arithmatex">\(O(\log n)\)</span> あるいは <span class="arithmatex">\(O(1)\)</span> の高速な検索を実現します。</p>
<p>空間資源が貴重な場面では、時間を犠牲にして空間を得ることもあります。たとえば組み込み開発では、デバイスのメモリが非常に貴重なため、エンジニアはハッシュテーブルの使用をやめ、配列による順次探索を選んでメモリ使用量を節約することがあります。その代償として探索は遅くなります。</p>
<!-- Source file information -->