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; ハッシュテーブル
@@ -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; ヒープ構築
@@ -2602,7 +2602,7 @@
<span class="md-ellipsis">
10.2 &nbsp; 二分探索の挿入
10.2 &nbsp; 二分探索の挿入位置
@@ -2658,7 +2658,7 @@
<span class="md-ellipsis">
10.4 &nbsp; ハッシュ最適化戦略
10.4 &nbsp; ハッシュによる最適化戦略
@@ -2686,7 +2686,7 @@
<span class="md-ellipsis">
10.5 &nbsp; 探索アルゴリズムの再認識
10.5 &nbsp; 探索アルゴリズム再考
@@ -3224,7 +3224,7 @@
<span class="md-ellipsis">
12.1 &nbsp; 分割統治アルゴリズム
12.1 &nbsp; 分割統治
@@ -3280,7 +3280,7 @@
<span class="md-ellipsis">
12.3 &nbsp; 木の構築問題
12.3 &nbsp; 二分木の構築問題
@@ -3308,7 +3308,7 @@
<span class="md-ellipsis">
12.4 &nbsp; ハノイの塔問題
12.4 &nbsp; ハノイの塔問題
@@ -3501,7 +3501,7 @@
<span class="md-ellipsis">
13.3 &nbsp; 部分集合和問題
13.3 &nbsp; 部分和問題
@@ -3529,7 +3529,7 @@
<span class="md-ellipsis">
13.4 &nbsp; Nクイーン問題
13.4 &nbsp; n クイーン問題
@@ -3670,7 +3670,7 @@
<span class="md-ellipsis">
14.1 &nbsp; 動的計画法の初歩
14.1 &nbsp; 動的計画法入門
@@ -3698,7 +3698,7 @@
<span class="md-ellipsis">
14.2 &nbsp; DP 問題特性
14.2 &nbsp; 動的計画法の問題特性
@@ -3726,7 +3726,7 @@
<span class="md-ellipsis">
14.3 &nbsp; DP の解法の考え方
14.3 &nbsp; 動的計画法の問題解決の考え方
@@ -3754,7 +3754,7 @@
<span class="md-ellipsis">
14.4 &nbsp; 0-1ナップサック問題
14.4 &nbsp; 0-1 ナップサック問題
@@ -3947,7 +3947,7 @@
<span class="md-ellipsis">
15.1 &nbsp; 貪欲アルゴリズム
15.1 &nbsp; 貪欲
@@ -4192,7 +4192,7 @@
<span class="md-ellipsis">
16.2 &nbsp; 一緒に作に参加する
16.2 &nbsp; 一緒に作に参加しましょう
@@ -4433,7 +4433,7 @@
<!-- Page content -->
<h1 id="91">9.1 &nbsp; グラフ<a class="headerlink" href="#91" title="Permanent link">&para;</a></h1>
<p><u>グラフ</u>非線形データ構造の一種で<u>頂点</u><u></u>構成されす。グラフ<span class="arithmatex">\(G\)</span>は、頂点集合<span class="arithmatex">\(V\)</span>と辺集合<span class="arithmatex">\(E\)</span>の組み合わせとして抽象的に表現できます。以下の例は、5の頂点と7つの辺を含むグラフを示しています。</p>
<p><u>グラフgraph</u>は、<u>頂点vertex</u><u>edge</u>から構成される非線形データ構造です。グラフ <span class="arithmatex">\(G\)</span> は、頂点集合 <span class="arithmatex">\(V\)</span> と辺集合 <span class="arithmatex">\(E\)</span> からなる集合として抽象的に表ます。以下の例は、5の頂点と 7 本の辺を含むグラフを示しています。</p>
<div class="arithmatex">\[
\begin{aligned}
V &amp; = \{ 1, 2, 3, 4, 5 \} \newline
@@ -4441,62 +4441,62 @@ E &amp; = \{ (1,2), (1,3), (1,5), (2,3), (2,4), (2,5), (4,5) \} \newline
G &amp; = \{ V, E \} \newline
\end{aligned}
\]</div>
<p>頂点をノード、辺をノードを接続する参照(ポインタ)と見なすと、グラフは連結リストから拡張されたデータ構造として見ることができます。図に示すように、<strong>線形関係(連結リスト)や分割統治関係(木)と比較して、ネットワーク関係(グラフ)は自由度が高いため、より複雑です</strong></p>
<p>頂点をノード、辺をノードをつなぐ参照(ポインタ)とみなせば、グラフは連結リストを拡張したデータ構造の一種と捉えられます。次の図に示すように、<strong>線形関係(連結リスト)や分治関係(木)と比て、ネットワーク関係(グラフ)は自由度が高</strong>、そのぶん複雑です</p>
<p><img alt="連結リスト、木、グラフの関係" class="animation-figure" src="../graph.assets/linkedlist_tree_graph.png" /></p>
<p align="center"> 図 9-1 &nbsp; 連結リスト、木、グラフの関係 </p>
<h2 id="911">9.1.1 &nbsp; グラフの一般的な種類と用語<a class="headerlink" href="#911" title="Permanent link">&para;</a></h2>
<p>グラフは、辺に方向があるかどうかによって<u>無向グラフ</u><u>有向グラフ</u>に分けることができます(下図参照)</p>
<p>辺が方向性を持つかどうかに応じて、<u>無向グラフundirected graph</u><u>有向グラフdirected graph</u>に分けられます。次の図のとおりです</p>
<ul>
<li>無向グラフでは、辺は2つの頂点間の「双方向」接続を表します。例えば、Facebookの「友達」関係です。</li>
<li>有向グラフでは、辺方向性があります。つまり、辺<span class="arithmatex">\(A \rightarrow B\)</span><span class="arithmatex">\(A \leftarrow B\)</span>は互いに独立しています。例えば、InstagramやTikTokの「フォロー」と「フォロワー」の関係です。</li>
<li>無向グラフでは、辺は 2 つの頂点間の「双方向」接続関係を表します。例えば WeChat や QQ における「友だち関係です。</li>
<li>有向グラフでは、辺方向性を持ち、すなわち <span class="arithmatex">\(A \rightarrow B\)</span><span class="arithmatex">\(A \leftarrow B\)</span> の 2 方向の辺は互いに独立す。例えば Weibo や Douyin における「フォロー」と「フォロワー」の関係です。</li>
</ul>
<p><img alt="有向グラフと無向グラフ" class="animation-figure" src="../graph.assets/directed_graph.png" /></p>
<p align="center"> 図 9-2 &nbsp; 有向グラフと無向グラフ </p>
<p>すべての頂点が接続されているかどうかによって、グラフは<u>連結グラフ</u><u>非連結グラフ</u>に分けることができます(下図参照)</p>
<p>すべての頂点が連結しているかどうかに応じて、<u>連結グラフconnected graph</u><u>非連結グラフdisconnected graph</u>に分けられます。次の図のとおりです</p>
<ul>
<li>連結グラフでは、任意の頂点から開始して他の任意の頂点に到達することが可能です。</li>
<li>非連結グラフでは、任意の開始頂点から到達できない頂点が少なくとも1つ存在します</li>
<li>連結グラフでは、ある頂点から出発すると、ほかの任意の頂点に到達できます。</li>
<li>非連結グラフでは、ある頂点から出発すると、少なくとも 1 つの頂点には到達できません</li>
</ul>
<p><img alt="連結グラフと非連結グラフ" class="animation-figure" src="../graph.assets/connected_graph.png" /></p>
<p align="center"> 図 9-3 &nbsp; 連結グラフと非連結グラフ </p>
<p>辺に重み変数を追加することもでき、その結果として<u>重み付きグラフ</u>生まれます(下図参照)。例えば、Instagramでは、システムがあなたと他のユーザーとの間の相互作用レベル(いいね、閲覧、コメントなど)によってフォロワーとフォロー中のリストをソートします。このような相互作用ネットワークは重み付きグラフで表現できます。</p>
<p>辺に重み」の変数を追加すると、次の図に示すような<u>重み付きグラフweighted graph</u>得られます。例えば『Honor of Kings』のようなモバイルゲームでは、システムが共にプレイした時間に基づいてプレイヤー間の「親密度」を計算します。この親密度ネットワークは重み付きグラフで表ます。</p>
<p><img alt="重み付きグラフと重みなしグラフ" class="animation-figure" src="../graph.assets/weighted_graph.png" /></p>
<p align="center"> 図 9-4 &nbsp; 重み付きグラフと重みなしグラフ </p>
<p>グラフデータ構造には、以下のような一般的に使用される用語があります。</p>
<p>グラフというデータ構造には、のような基本用語があります。</p>
<ul>
<li><u>隣接</u>2つの頂点を接続する辺がある場合、これら2つの頂点は「隣接していると言われます。上図では、頂点1の隣接頂点は頂点2、3、5です。</li>
<li><u>パス</u>:頂点Aから頂点Bまでに通過する辺のシーケンスを、AからBへのパスと呼びます。上図では、辺のシーケンス1-5-2-4は頂点1から頂点4へのパスです。</li>
<li><u>次数</u>:頂点が持つ辺の数です。有向グラフの場合<u>入次数</u>はその頂点を指す辺の数<u>出次数</u>はその頂点から出る辺の数をします。</li>
<li><u>隣接adjacency</u>2 つの頂点の間に辺が存在するとき、この 2 つの頂点は「隣接している」といいます。上図では、頂点 1 に隣接する頂点は 2、3、5 です。</li>
<li><u>経路(path</u>:頂点 A から頂点 B までに通過する辺で構成された列を、A から B への「経路」と呼びます。上図では、辺の1-5-2-4 は頂点 1 から頂点 4 への 1 本の経路です。</li>
<li><u>次数degree</u>ある頂点が持つ辺の数です。有向グラフでは<u>入次数in-degree</u>はその頂点に向かう辺の本数を表し<u>出次数out-degree</u>はその頂点から出る辺の数をします。</li>
</ul>
<h2 id="912">9.1.2 &nbsp; グラフの表現<a class="headerlink" href="#912" title="Permanent link">&para;</a></h2>
<p>グラフの一般的な表現には「隣接行列」と「隣接リスト」があります。以下の例では無向グラフを使用します。</p>
<p>グラフの一般的な表現方法には「隣接行列」と「隣接リスト」があります。以下では無向グラフを例に説明します。</p>
<h3 id="1">1. &nbsp; 隣接行列<a class="headerlink" href="#1" title="Permanent link">&para;</a></h3>
<p>グラフの頂点数を<span class="arithmatex">\(n\)</span>とすると、<u>隣接行列</u><span class="arithmatex">\(n \times n\)</span>の行列を使用してグラフを表します。各行(列)は頂点を表し、行列要素は辺を表し、2つの頂点間に辺があるかどうかを<span class="arithmatex">\(1\)</span>または<span class="arithmatex">\(0\)</span>示します。</p>
<p>下図に示すように、隣接行列を<span class="arithmatex">\(M\)</span>、頂点リストを<span class="arithmatex">\(V\)</span>とすると、行列要素<span class="arithmatex">\(M[i, j] = 1\)</span>は頂点<span class="arithmatex">\(V[i]\)</span>頂点<span class="arithmatex">\(V[j]\)</span>の間に辺があることをし、逆に<span class="arithmatex">\(M[i, j] = 0\)</span>は2つの頂点間に辺がないことをします。</p>
<p><img alt="隣接行列によるグラフの表現" class="animation-figure" src="../graph.assets/adjacency_matrix.png" /></p>
<p align="center"> 図 9-5 &nbsp; 隣接行列によるグラフの表現 </p>
<p>グラフの頂点数を <span class="arithmatex">\(n\)</span> とすると、<u>隣接行列adjacency matrix</u> <span class="arithmatex">\(n \times n\)</span> の行列を用いてグラフを表します。各行(列)は 1 つの頂点を表し、行列要素は辺を表します。<span class="arithmatex">\(1\)</span> または <span class="arithmatex">\(0\)</span> を用いて、2 つの頂点の間に辺があるかどうかを示します。</p>
<p>次の図のように、隣接行列を <span class="arithmatex">\(M\)</span>、頂点リストを <span class="arithmatex">\(V\)</span> とすると、行列要素 <span class="arithmatex">\(M[i, j] = 1\)</span> は頂点 <span class="arithmatex">\(V[i]\)</span> から頂点 <span class="arithmatex">\(V[j]\)</span> への辺が存在することをし、逆に <span class="arithmatex">\(M[i, j] = 0\)</span> は 2 つの頂点間に辺がないことをします。</p>
<p><img alt="グラフの隣接行列による表現" class="animation-figure" src="../graph.assets/adjacency_matrix.png" /></p>
<p align="center"> 図 9-5 &nbsp; グラフの隣接行列による表現 </p>
<p>隣接行列には以下の特があります。</p>
<p>隣接行列にはの特があります。</p>
<ul>
<li>頂点は自分自身に接続することはできないため、隣接行列の主対角線上の要素は意味がありません。</li>
<li>無向グラフの場合、両方向の辺は等価であるため、隣接行列は主対角線に関して対称です。</li>
<li>隣接行列の要素を<span class="arithmatex">\(1\)</span><span class="arithmatex">\(0\)</span>から重みに置き換えることで、重み付きグラフを表現できます。</li>
<li>単純グラフでは、頂点は自分自身とは接続できないため、このとき隣接行列の主対角線上の要素は意味がありません。</li>
<li>無向グラフでは、2 方向の辺は等価であるため、このとき隣接行列は主対角線に関して対称です。</li>
<li>隣接行列の要素を <span class="arithmatex">\(1\)</span><span class="arithmatex">\(0\)</span> から重みに置き換える、重み付きグラフを表ます。</li>
</ul>
<p>隣接行列でグラフを表現する場合、行列要素に直接アクセスして辺を取得できるため、追加削除検索、変更の操作効率的で、すべて時間計算量<span class="arithmatex">\(O(1)\)</span>です。ただし、行列の空間計算量は<span class="arithmatex">\(O(n^2)\)</span>で、より多くのメモリを消費します。</p>
<p>隣接行列でグラフを表場合、行列要素に直接アクセスして辺を取得できるため、追加削除検索・更新の操作効率は高く、時間計算量はいずれも <span class="arithmatex">\(O(1)\)</span> です。しかし、行列の空間計算量は <span class="arithmatex">\(O(n^2)\)</span> であり、メモリ使用量は多くなります。</p>
<h3 id="2">2. &nbsp; 隣接リスト<a class="headerlink" href="#2" title="Permanent link">&para;</a></h3>
<p><u>隣接リスト</u><span class="arithmatex">\(n\)</span>の連結リストを使用してグラフを表現し、各連結リストノードは頂点を表します。<span class="arithmatex">\(i\)</span>番目の連結リストは頂点<span class="arithmatex">\(i\)</span>に対応し、すべての隣接頂点(その頂点接続された頂点)を含みます。図は隣接リストを使用して格納されたグラフの例を示しています。</p>
<p><img alt="隣接リストによるグラフの表現" class="animation-figure" src="../graph.assets/adjacency_list.png" /></p>
<p align="center"> 図 9-6 &nbsp; 隣接リストによるグラフの表現 </p>
<p><u>隣接リストadjacency list</u><span class="arithmatex">\(n\)</span>の連結リストを使てグラフを表します。連結リストノードは頂点を表します。<span class="arithmatex">\(i\)</span>の連結リストは頂点 <span class="arithmatex">\(i\)</span> に対応し、その頂点に隣接するすべての頂点(その頂点接続された頂点)を格納します。次の図は隣接リストで保存したグラフの例です。</p>
<p><img alt="グラフの隣接リストによる表現" class="animation-figure" src="../graph.assets/adjacency_list.png" /></p>
<p align="center"> 図 9-6 &nbsp; グラフの隣接リストによる表現 </p>
<p>隣接リストは実際の辺のみを格納し、辺の総数は<span class="arithmatex">\(n^2\)</span>よりはるかに少ないことが多く、より空間効率的です。ただし、隣接リストで辺を見つけるに連結リストを走査する必要があるため、その時間効率は隣接行列ほど良くありません。</p>
<p>上図を観察すると、<strong>隣接リストの構造はハッシュテーブルの「チェイン法」と非常に似ているため、同様の方法を使用して効率を最適化できます</strong>。例えば、連結リストが長い場合、それをAVL木や赤黒木に変換して時間効率を<span class="arithmatex">\(O(n)\)</span>から<span class="arithmatex">\(O(\log n)\)</span>に最適化できます。連結リストをハッシュテーブルに変換することで、時間計算量を<span class="arithmatex">\(O(1)\)</span>に削減することもできます。</p>
<p>隣接リストは実際に存在する辺だけを格納し、辺の総数は通常 <span class="arithmatex">\(n^2\)</span> よりはるかに小さいため、より省スペースです。しかし、隣接リストで辺を見つけるために連結リストを走査する必要があるため、時間効率は隣接行列に及びません。</p>
<p>上図をると、<strong>隣接リストの構造はハッシュテーブルにおける「連鎖アドレス法」と非常によく似ているため、同様の方法効率を最適化できます</strong>。例えば、連結リストが長い場合AVL 木や赤黒木に変換して時間効率を <span class="arithmatex">\(O(n)\)</span> から <span class="arithmatex">\(O(\log n)\)</span> に改善できます。さらに、連結リストをハッシュテーブルに変換すれば、時間計算量を <span class="arithmatex">\(O(1)\)</span> まで下げられます。</p>
<h2 id="913">9.1.3 &nbsp; グラフの一般的な応用<a class="headerlink" href="#913" title="Permanent link">&para;</a></h2>
<p>下表に示すように、多くの現実世界のシステムはグラフでモデル化でき、対応する問題グラフ計算問題に削減できます。</p>
<p align="center"> 表 9-1 &nbsp; 現実生活の一般的なグラフ </p>
<p>次の表のように、多くの現実のシステムはグラフでモデル化でき、対応する問題グラフ計算問題に帰着できます。</p>
<p align="center"> 表 9-1 &nbsp; 現実世界でよく見られるグラフ </p>
<div class="center-table">
<table>
@@ -4512,20 +4512,20 @@ G &amp; = \{ V, E \} \newline
<tr>
<td>ソーシャルネットワーク</td>
<td>ユーザー</td>
<td>フォロー / フォロワー関係</td>
<td>潜在的フォロー推薦</td>
<td>友だち関係</td>
<td>潜在的な友だちの推薦</td>
</tr>
<tr>
<td>地下鉄路線</td>
<td></td>
<td>駅間の接続性</td>
<td>最短ルート推薦</td>
<td>最短経路の推薦</td>
</tr>
<tr>
<td>太陽系</td>
<td>天体</td>
<td>天体間の重力</td>
<td>惑星軌道計算</td>
<td>天体間の万有引力作用</td>
<td>惑星軌道計算</td>
</tr>
</tbody>
</table>