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">
@@ -39,7 +39,7 @@
<title>10.5 探索アルゴリズムの再検討 - Hello アルゴリズム</title>
<title>10.5 探索アルゴリズム再考 - Hello アルゴリズム</title>
@@ -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>
@@ -152,7 +152,7 @@
<div class="md-header__topic" data-md-component="header-topic">
<span class="md-ellipsis">
10.5 &nbsp; 探索アルゴリズムの再検討
10.5 &nbsp; 探索アルゴリズム再考
</span>
</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; ハッシュテーブル
@@ -1942,7 +1942,7 @@
<span class="md-ellipsis">
7.5 &nbsp; AVL木 *
7.5 &nbsp; AVL 木 *
@@ -2105,7 +2105,7 @@
<span class="md-ellipsis">
8.2 &nbsp; ヒープ構築操作
8.2 &nbsp; ヒープ構築
@@ -2493,7 +2493,7 @@
<span class="md-ellipsis">
10.2 &nbsp; 二分探索の挿入
10.2 &nbsp; 二分探索の挿入位置
@@ -2549,7 +2549,7 @@
<span class="md-ellipsis">
10.4 &nbsp; ハッシュ最適化戦略
10.4 &nbsp; ハッシュによる最適化戦略
@@ -2586,7 +2586,7 @@
<span class="md-ellipsis">
10.5 &nbsp; 探索アルゴリズムの再認識
10.5 &nbsp; 探索アルゴリズム再考
@@ -2604,7 +2604,7 @@
<span class="md-ellipsis">
10.5 &nbsp; 探索アルゴリズムの再認識
10.5 &nbsp; 探索アルゴリズム再考
@@ -2645,7 +2645,7 @@
<a href="#1052" class="md-nav__link">
<span class="md-ellipsis">
10.5.2 &nbsp; 適応的探索
10.5.2 &nbsp; 適応的探索
</span>
</a>
@@ -2656,7 +2656,7 @@
<a href="#1053" class="md-nav__link">
<span class="md-ellipsis">
10.5.3 &nbsp; 探索法の選択
10.5.3 &nbsp; 探索法の選択
</span>
</a>
@@ -3196,7 +3196,7 @@
<span class="md-ellipsis">
12.1 &nbsp; 分割統治アルゴリズム
12.1 &nbsp; 分割統治
@@ -3252,7 +3252,7 @@
<span class="md-ellipsis">
12.3 &nbsp; 木の構築問題
12.3 &nbsp; 二分木の構築問題
@@ -3280,7 +3280,7 @@
<span class="md-ellipsis">
12.4 &nbsp; ハノイの塔問題
12.4 &nbsp; ハノイの塔問題
@@ -3473,7 +3473,7 @@
<span class="md-ellipsis">
13.3 &nbsp; 部分集合和問題
13.3 &nbsp; 部分和問題
@@ -3501,7 +3501,7 @@
<span class="md-ellipsis">
13.4 &nbsp; Nクイーン問題
13.4 &nbsp; n クイーン問題
@@ -3642,7 +3642,7 @@
<span class="md-ellipsis">
14.1 &nbsp; 動的計画法の初歩
14.1 &nbsp; 動的計画法入門
@@ -3670,7 +3670,7 @@
<span class="md-ellipsis">
14.2 &nbsp; DP 問題特性
14.2 &nbsp; 動的計画法の問題特性
@@ -3698,7 +3698,7 @@
<span class="md-ellipsis">
14.3 &nbsp; DP の解法の考え方
14.3 &nbsp; 動的計画法の問題解決の考え方
@@ -3726,7 +3726,7 @@
<span class="md-ellipsis">
14.4 &nbsp; 0-1ナップサック問題
14.4 &nbsp; 0-1 ナップサック問題
@@ -3919,7 +3919,7 @@
<span class="md-ellipsis">
15.1 &nbsp; 貪欲アルゴリズム
15.1 &nbsp; 貪欲
@@ -4164,7 +4164,7 @@
<span class="md-ellipsis">
16.2 &nbsp; 一緒に作に参加する
16.2 &nbsp; 一緒に作に参加しましょう
@@ -4321,7 +4321,7 @@
<a href="#1052" class="md-nav__link">
<span class="md-ellipsis">
10.5.2 &nbsp; 適応的探索
10.5.2 &nbsp; 適応的探索
</span>
</a>
@@ -4332,7 +4332,7 @@
<a href="#1053" class="md-nav__link">
<span class="md-ellipsis">
10.5.3 &nbsp; 探索法の選択
10.5.3 &nbsp; 探索法の選択
</span>
</a>
@@ -4376,42 +4376,42 @@
<!-- Page content -->
<h1 id="105">10.5 &nbsp; 探索アルゴリズムの再検討<a class="headerlink" href="#105" title="Permanent link">&para;</a></h1>
<p><u>探索アルゴリズム(検索アルゴリズム</u>は、配列、連結リスト、木、グラフなどのデータ構造内で特定の基準を満たす1つ以上の要素を取得するために使用されます。</p>
<p>探索アルゴリズムは、そのアプローチに基づいて以下の2つのカテゴリに分けることができます。</p>
<h1 id="105">10.5 &nbsp; 探索アルゴリズム再考<a class="headerlink" href="#105" title="Permanent link">&para;</a></h1>
<p><u>探索アルゴリズム(searching algorithm</u>は、データ構造(配列、連結リスト、木、グラフなど)の中から、特定の条件を満たす 1 つまたは複数の要素を探索するために用いられます。</p>
<p>探索アルゴリズムは、実装の考え方に応じて次の 2 種類に分けられます。</p>
<ul>
<li><strong>データ構造を横断することで目標要素を特定する</strong>配列、連結リスト、木、グラフの横断など</li>
<li><strong>データの組織構造や既存のデータを使用して効率的な要素探索を実現する</strong>二分探索、ハッシュ探索、二分探索木探索など。</li>
<li><strong>データ構造を走査して目標要素を特定する方法</strong>配列、連結リスト、木、グラフの走査などがこれに当たります</li>
<li><strong>データの構成やデータに含まれる事前情報を利用して、要素を効率よく探す方法</strong>二分探索、ハッシュ探索、二分探索木による探索などがこれに当たります</li>
</ul>
<p>これらのトピックは前の章で紹介されたため、私たちには馴染みのないものではありません。このセクションでは、より体系的な点から探索アルゴリズムを再検討します。</p>
<p>これらのトピックはすでに前の章で扱っているため、探索アルゴリズムは私たちにとって見慣れたものです。本節では、より体系的な点から探索アルゴリズムをあらためて見直します。</p>
<h2 id="1051">10.5.1 &nbsp; 総当たり探索<a class="headerlink" href="#1051" title="Permanent link">&para;</a></h2>
<p>総当たり探索は、データ構造のすべての要素を横断することで目標要素を特定します。</p>
<p>総当たり探索は、データ構造の各要素を順に調べて目標要素を特定します。</p>
<ul>
<li>線形探索は配列や連結リストなどの線形データ構造に適しています。データ構造の一端から開始し、目標要素が見つかるか、目標要素を見つけることなく他端に到達するまで、各要素に一つずつアクセスします。</li>
<li>幅優先探索」と「深さ優先探索は、グラフと木の2つの横断戦略です。幅優先探索は初期ノードから開始し、層ごと(左から右へ)に探索し、近くから遠くのノードにアクセスします。深さ優先探索は初期ノードから開始し、パスの終端(上から下へ)まで追跡し、その後バックトラックして他のパスを試し、データ構造全体が横断されるまで続行します。</li>
<li>線形探索は配列や連結リストなどの線形データ構造に適しています。データ構造の一端から始めて、要素を 1 つずつ調べ、目標要素が見つかるか、もう一方の端に達しても見つからないまで続けます。</li>
<li>幅優先探索”と“深さ優先探索は、グラフと木における 2 つの走査戦略です。幅優先探索は初期ノードから始めて層ごとに探索し、近いところから遠いところへ各ノードを訪れます。深さ優先探索は初期ノードから始めて 1 本の経路を最後までたどり、その後バックトラックしてほかの経路を試し、データ構造全体を走査し終えるまで続ます。</li>
</ul>
<p>総当たり探索の利点は、その単純さと汎用性であり、**データの前処理や追加のデータ構造の助けが不要**です。</p>
<p>ただし、**このタイプのアルゴリズムの時間計算量は<span class="arithmatex">\(O(n)\)</span>**で、<span class="arithmatex">\(n\)</span>は要素数であるため、大規模なデータセットでは性能がくなります。</p>
<h2 id="1052">10.5.2 &nbsp; 適応的探索<a class="headerlink" href="#1052" title="Permanent link">&para;</a></h2>
<p>適応的探索は、データ固有の性質(順序など)を使用して探索プロセスを最適化し、それにより目標要素をより効率的に特定します。</p>
<p>総当たり探索の利点は、単純で汎用性が高く、**データの前処理や追加のデータ構造を必要としない**ことです。</p>
<p>しかし、<strong>この種のアルゴリズムの時間計算量は <span class="arithmatex">\(O(n)\)</span> です</strong>。ここで <span class="arithmatex">\(n\)</span> は要素数であり、そのためデータ量が大きい場合は性能がくなります。</p>
<h2 id="1052">10.5.2 &nbsp; 適応的探索<a class="headerlink" href="#1052" title="Permanent link">&para;</a></h2>
<p>適応的探索は、データが持つ固有の性質(整列性など)を用して探索過程を最適化し、目標要素をより効率よく特定します。</p>
<ul>
<li>二分探索」はデータの整列性を使用して効率的な探索を実現し、配列にのみ適用可能です</li>
<li>ハッシュ探索」はハッシュテーブルを使用して探索データと目標データの間にキーと値のマッピングを確立し、それによりクエリ操作を実します。</li>
<li>特定の木構造(二分探索木など)での「木探索」は、ノード値の比較に基づいてノードを迅速に除外し、それにより目標要素を特定します。</li>
<li>二分探索”は、データの順序性を用して効率的な探索を行う方法で、配列にしか適用できません</li>
<li>ハッシュ探索”は、ハッシュ表を用いて探索対象のデータと目標データキーと値の対応にし、問い合わせ操作を実します。</li>
<li>“木探索”は、特定の木構造(たとえば二分探索木)の中で、ノード値の比較に基づいて不要なノードをすばやく除外し、目標要素を特定します。</li>
</ul>
<p>れらのアルゴリズムの利点は効率であり、<strong>時間計算量が<span class="arithmatex">\(O(\log n)\)</span>または<span class="arithmatex">\(O(1)\)</span>にまで達します</strong></p>
<p>ただし、<strong>これらのアルゴリズムを使用するには、多くの場合データの前処理が必要です</strong>えば、二分探索では事前に配列をソートする必要があり、ハッシュ探索と木探索の両方で追加のデータ構造の助けが必要です。これらの構造を維持することも、時間と空間の面でより多くのオーバーヘッドが必要です。</p>
<p>の種のアルゴリズムの利点は効率が高く、**時間計算量が <span class="arithmatex">\(O(\log n)\)</span> あるいは <span class="arithmatex">\(O(1)\)</span> に達する**ことです</p>
<p>しかし、<strong>これらのアルゴリズムを使うには、たいていデータの前処理が必要です</strong>たとえば、二分探索では事前に配列をソートする必要があり、ハッシュ探索と木探索で追加のデータ構造が必要です。これらのデータ構造を維持するにも、追加の時間と空間のコストがかかります。</p>
<div class="admonition tip">
<p class="admonition-title">Tip</p>
<p>適応的探索アルゴリズムは、多くの場合探索アルゴリズムと呼ばれ、<strong>主に特定のデータ構造で目標要素を速に取得するために使用されます</strong></p>
<p>適応的探索アルゴリズムは、しばしば検索アルゴリズムと呼ばれ、<strong>主に特定のデータ構造の中で目標要素を速に取得するために用いられます</strong></p>
</div>
<h2 id="1053">10.5.3 &nbsp; 探索法の選択<a class="headerlink" href="#1053" title="Permanent link">&para;</a></h2>
<p>サイズ<span class="arithmatex">\(n\)</span>のデータセットが与えられた場合、線形探索、二分探索、木探索、ハッシュ探索、またはその他の方法を使用して目標要素を取得できます。これらの方法の動作原理を下図に示します。</p>
<p><img alt="Various search strategies" class="animation-figure" src="../searching_algorithm_revisited.assets/searching_algorithms.png" /></p>
<p align="center"> 図 10-11 &nbsp; Various search strategies </p>
<h2 id="1053">10.5.3 &nbsp; 探索法の選択<a class="headerlink" href="#1053" title="Permanent link">&para;</a></h2>
<p>大きさ <span class="arithmatex">\(n\)</span> のデータ集合が与えられたとき、線形探索、二分探索、木探索、ハッシュ探索など、さまざまな方法で目標要素を探索できます。各手法の動作原理を下図に示します。</p>
<p><img alt="複数の探索戦略" class="animation-figure" src="../searching_algorithm_revisited.assets/searching_algorithms.png" /></p>
<p align="center"> 図 10-11 &nbsp; 複数の探索戦略 </p>
<p>前述の方法の特性と操作効率を以下の表に示します。</p>
<p align="center"> 表 10-1 &nbsp; 探索アルゴリズム効率比較 </p>
<p>上記のいくつかの手法について、操作効率と特性を次の表に示します。</p>
<p align="center"> 表 10-1 &nbsp; 探索アルゴリズム効率比較 </p>
<div class="center-table">
<table>
@@ -4447,7 +4447,7 @@
<td><span class="arithmatex">\(O(1)\)</span></td>
</tr>
<tr>
<td>追加空間</td>
<td>追加領域</td>
<td><span class="arithmatex">\(O(1)\)</span></td>
<td><span class="arithmatex">\(O(1)\)</span></td>
<td><span class="arithmatex">\(O(n)\)</span></td>
@@ -4458,44 +4458,44 @@
<td>/</td>
<td>ソート <span class="arithmatex">\(O(n \log n)\)</span></td>
<td>木構築 <span class="arithmatex">\(O(n \log n)\)</span></td>
<td>ハッシュテーブル構築 <span class="arithmatex">\(O(n)\)</span></td>
<td>ハッシュ構築 <span class="arithmatex">\(O(n)\)</span></td>
</tr>
<tr>
<td>データ順序性</td>
<td>無順序</td>
<td>順序</td>
<td>順序</td>
<td>無順序</td>
<td>データ順序性</td>
<td>なし</td>
<td>あり</td>
<td>あり</td>
<td>なし</td>
</tr>
</tbody>
</table>
</div>
<p>探索アルゴリズムの選択は、データ量、探索性能要件、データクエリと更新頻度などにも依存します。</p>
<p>探索アルゴリズムの選択は、規模、探索性能の要求、データの問い合わせ頻度や更新頻度などにも左右されます。</p>
<p><strong>線形探索</strong></p>
<ul>
<li>汎用性がく、データ前処理操作が不要です。データを一度だけクエリする必要がある場合、他の3つの方法のデータ前処理時間は線形探索の時間より長くなります。</li>
<li>小容量のデータに適しており、時間計算量が効率に与える影響は小さいです。</li>
<li>データ更新が非常に頻繁なシナリオに適しています。この方法はデータの追加メンテナンスを必要としないためです。</li>
<li>汎用性がく、データ前処理をまったく必要としません。データを 1 回だけ問い合わせればよい場合、ほか 3 つの手法では前処理にかかる時間のほうが、線形探索そのものより長くなることがあります。</li>
<li>規模の小さいデータに適しています。この場合、時間計算量が効率に与える影響は比較的小さいです。</li>
<li>データ更新頻度が高い場面に適しています。この手法では、データに対する追加の保守が不要だからです。</li>
</ul>
<p><strong>二分探索</strong></p>
<ul>
<li>より大きなデータに適しており、安定した性能と最悪ケースの時間計算量<span class="arithmatex">\(O(\log n)\)</span>を持ちます。</li>
<li>ただし、データ量が大きすぎることはできません。配列の保存には連続したメモリ空間が必要だからです。</li>
<li>頻繁な追加と削除があるシナリオには適していません。順序付き配列維持に多くのオーバーヘッドが発生するためです。</li>
<li>大規模データに適しており、効率が安定しています。最悪時間計算量<span class="arithmatex">\(O(\log n)\)</span>す。</li>
<li>データ量が大きすぎる場合には向きません。配列の格納には連続したメモリ領域が必要だからです。</li>
<li>頻繁な挿入・削除がある場面には向きません。整列配列維持するコストが高いためです。</li>
</ul>
<p><strong>ハッシュ探索</strong></p>
<ul>
<li>高速クエリ性能が不可欠なシナリオに適しており、平均時間計算量は<span class="arithmatex">\(O(1)\)</span>です。</li>
<li>順序付きデータや範囲探索が必要なシナリオには適していません。ハッシュテーブルはデータの順序性を維持できないためです。</li>
<li>問い合わせ性能への要求が高い場面に適しており、平均時間計算量は <span class="arithmatex">\(O(1)\)</span> です。</li>
<li>順序付きデータや範囲探索が必要な場面には向きません。ハッシュ表ではデータの順序性を維持できないからです。</li>
<li>ハッシュ関数とハッシュ衝突処理戦略への依存度が高く、性能劣化のリスクが大きいです。</li>
<li>過度に大容量のデータには適していません。ハッシュテーブルは衝突を最小化し、良好なクエリ性能を提供するために追加の空間必要からです。</li>
<li>データ量が大きすぎる場合には向きません。ハッシュ表は衝突をできるだけ減らして良好な問い合わせ性能を出すために追加の空間必要とするからです。</li>
</ul>
<p><strong>木探索</strong></p>
<ul>
<li>容量データに適しています。木ノードはメモリに分散して保存されるためです。</li>
<li>順序付きデータの維持や範囲探索に適しています。</li>
<li>ノードの継続的な追加と削除により、二分探索木は偏る可能性があり、時間計算量<span class="arithmatex">\(O(n)\)</span>劣化する可能性があります。</li>
<li>AVL木や赤黒木を使用する場合、操作は<span class="arithmatex">\(O(\log n)\)</span>効率で安定して実行できますが、木のバランスを維持する操作によ追加のオーバーヘッドが追加されます。</li>
<li>大データに適しています。木ノードはメモリに分散して格納されるためです。</li>
<li>順序付きデータの維持や範囲探索が必要な場面に適しています。</li>
<li>ノードの挿入・削除を続ける過程で、二分探索木は偏ることがあり、時間計算量<span class="arithmatex">\(O(n)\)</span> まで劣化する可能性があります。</li>
<li>AVL 木や赤黒木を使えば、各種操作を <span class="arithmatex">\(O(\log n)\)</span>効率で安定して実行できますが、木の平衡を保つ処理によ追加コストが発生します。</li>
</ul>
<!-- Source file information -->
@@ -4519,7 +4519,7 @@ aria-label="フッター"
<a
href="../replace_linear_by_hashing/"
class="md-footer__link md-footer__link--prev"
aria-label="前: 10.4 &amp;nbsp; ハッシュ最適化戦略"
aria-label="前: 10.4 &amp;nbsp; ハッシュによる最適化戦略"
rel="prev"
>
<div class="md-footer__button md-icon">
@@ -4531,7 +4531,7 @@ aria-label="フッター"
</span>
<div class="md-ellipsis">
10.4 &nbsp; ハッシュ最適化戦略
10.4 &nbsp; ハッシュによる最適化戦略
</div>
</div>
</a>