Java優先度検索(DFS/BFS)の実用化
深さ優先検索DFS は深さ優先検索です。簡単に言うと、このプロセスは、それ以上深くは進めなくなり、各ノードには 1 回しかアクセスできないまで、考えられるすべての分岐パスをドリルダウンします。幅優先検索 BFS は幅優先検索です。ノードを展開して取得したすべての子ノードは、先入れ先出し キュー に追加されます。
DFS/BFS 検索アルゴリズム分析
定理 1: 開始点に接続されているすべての頂点をマークするために深さ優先検索に必要な時間は、頂点の次数の合計に比例します。
2 つの点 v と w があるとします。v が最初に w を訪問すると、辺 v-w は未チェックの状態から一度訪問されます。 w が v を訪問すると、辺 w-v が再度チェックされますが、この時点でこの辺はすでに 2 回訪問されていることがわかります。これ以外に、エッジ v-w (w-v) が訪問される可能性は他にありません。したがって、グラフ内の各エッジは 2 回アクセスされることがわかります。エッジ × 2 = 頂点 Σ 次数 (各頂点の次数の合計)。つまり正比例するのです。
定理 2: 一般に、深さ優先探索を使用して解決できる問題は、幅優先探索に変換できます。
深さ優先検索の利点は次のとおりです: 再帰理解しやすく、シンプルです。ただし、深さ優先探索には明確な目的がありませんが、幅優先探索は近くから遠くへ順番に探索し、最適解を見つけることができる場合が多く、ループは再帰よりも効率的であり、スタックオーバーフローのリスク。疎なグラフでの幅優先検索の効率は、深さ優先検索よりもはるかに高速であり、密なグラフでもほぼ同じです。幅優先検索が必ずしも必要でない場合は、深さ優先検索の使用を試みることができます。
定理 3: グラフ記録方法として隣接リストを使用する場合、深さ優先検索と幅優先検索の時間計算量は両方とも O(V+E) です。
要素へのアクセスに必要な時間は、主にグラフデータの記録方法に依存し、深さ優先検索か幅優先検索かにかかわらず、計算が完了する前にグラフ全体をチェックする必要があります。データを記録する方法として隣接行列を使用する場合、計算量は O(n2) となり、隣接リストには (頂点 + エッジの数 × 2) のデータのみが含まれます。エッジ数の半分だけを実行する必要があり、残りの半分の操作はチェックすることで省略できます。したがって、グラフ記録方法として隣接リストを使用する場合、DFS と BFS の両方の時間計算量は O(V+E) になります。
基本的なデータ構造 - グラフクラス
深さ優先アルゴリズムと幅優先アルゴリズムは、グラフ理論に基づいたアルゴリズムです。アプリケーションを実装する前に、まず基本的な 無向グラフ クラス データ構造を実装します。
Graph クラスは V を使用して固定点を定義し、E を使用してエッジを定義し、LinkedListInteger>[ ] を使用して隣接リストを定義します。
package Graph; import java.util.LinkedList; public class Graph { private final int V; private int E; private LinkedList<Integer>[] adj; public Graph(int V) { this.V = V; this.E = 0; adj = (LinkedList<Integer>[]) new LinkedList[V]; for (int v = 0; v < V; v++) adj[v] = new LinkedList<>(); } public int V() { return V; } public int E() { return E; } public void addEdge(int v, int w) { adj[v].add(w); adj[w].add(v); E++; } public LinkedList<Integer> adj(int v) { return adj[v]; } public int degree(int v,Graph g){ int count = 0; for(int s : adj(v)) count++; return count; } }
Graph クラスのジェネリック 配列
ジェネリック配列はここでのみ宣言され、通常の配列型変換によって実装されますが、セキュリティの隠れたリスクもあることに注意してください。
以下のようなプログラムはコンパイルに成功しますが、実行時にジェネリックが消去されるため、エラーが発生します。オブジェクト配列クラス間の代入はエラーを報告しません。
public static void main(String[] args) { LinkedList<Integer>[] adj; adj = (LinkedList<Integer>[]) new LinkedList[5]; Object o = adj; Object[] oa = (Object[]) o; List<String> li = new LinkedList<>(); li.add("s"); oa[0] = li; System.out.println(adj[0]); }
この状況を理解する必要がありますが、この記事では主にアルゴリズムを紹介するため、この部分についてはあまり説明しません。ここでエラーの可能性を列挙したいと思います。
接続性問題
package Graph; import java.util.ArrayDeque; import java.util.Queue; public class Connected { private Graph g; private boolean[] marked; private int count; public Connected(Graph g) { this.g = g; marked = new boolean[g.V()]; } /** * DFS算法计算连通结点 * * @param s * 起点 */ public void DFS(int s) { marked[s] = true; count++; for (int w : g.adj(s)) if (!marked[w]) DFS(w); } /** * BFS算法计算连通结点 * * @param s * 起点 */ public void BFS(int s) { Queue<Integer> q = new ArrayDeque<>(); q.add(s); marked[s] = true; count++; while (!q.isEmpty()) { for (int w : g.adj(q.poll())) if (!marked[w]) { marked[w] = true; count++; q.add(w); } } } /** * 初始化marked标记数组状态 */ public void cleanMarked() { for (boolean b : marked) b = false; } /** * 返回该起点总连通结点数 * * @return 连通结点数 */ public int count() { return count; } /** * 判断一个结点是否被连通 * * @param v * 判断结点 * @return 连通状态 */ public boolean isMarked(int v) { return marked[v]; } }
単一点経路問題
package Graph; import java.util.ArrayDeque; import java.util.Queue; import java.util.Stack; public class Paths { private Graph g; private boolean[] marked; private int[] edgeTo; public Paths(Graph g) { this.g = g; marked = new boolean[g.V()]; edgeTo = new int[g.V()]; } /** * DFS算法计算单点路径问题 * * @param s * 起点 */ public void DFS(int s) { marked[s] = true; for (int w : g.adj(s)) if (!marked[w]) { edgeTo[w] = s; DFS(w); } } /** * 初始化marked标记数组状态 */ public void cleanMarked() { for (boolean b : marked) b = false; } /** * 判断一个结点是否被连通 * * @param v * 判断结点 * @return 连通状态 */ public boolean isMarked(int v) { return marked[v]; } /** * 是否存在从s到v的路径,默认调用深度优先,可以选择广度优先 * * @param s * 起点 * @param v * 终点 * @return 存在状态 */ public boolean hasPathTo(int s, int v) { DFS(s); if (isMarked(v)) return true; return false; } }
単一点最短経路
package Graph; import java.util.ArrayDeque; import java.util.Queue; import java.util.Stack; public class Paths { private Graph g; private boolean[] marked; private int[] edgeTo; public Paths(Graph g) { this.g = g; marked = new boolean[g.V()]; edgeTo = new int[g.V()]; } /** * DFS算法计算单点路径问题 * * @param s * 起点 */ public void DFS(int s) { marked[s] = true; for (int w : g.adj(s)) if (!marked[w]) { edgeTo[w] = s; DFS(w); } } /** * BFS算法计算单点最短路径问题 * * @param s * 起点 */ public void BFS(int s) { Queue<Integer> q = new ArrayDeque<>(); q.add(s); marked[s] = true; while (!q.isEmpty()) { for (int w : g.adj(q.poll())) if (!marked[w]) { marked[w] = true; edgeTo[w] = s; q.add(w); } } } /** * 初始化marked标记数组状态 */ public void cleanMarked() { for (boolean b : marked) b = false; } /** * 判断一个结点是否被连通 * * @param v * 判断结点 * @return 连通状态 */ public boolean isMarked(int v) { return marked[v]; } /** * 是否存在从s到v的路径,默认调用深度优先,可以选择广度优先 * * @param s * 起点 * @param v * 终点 * @return 存在状态 */ public boolean hasPathTo(int s, int v) { DFS(s); // BFS(v); if (isMarked(v)) return true; return false; } /** * 输出最短路径 * * @param s * 起点 * @param v * 终点 */ public void pathTo(int s, int v) { if (!hasPathTo(s, v)) return; BFS(s); // DFS(s); 但深度优先可能不是最短路径 Stack<Integer> sta = new Stack<>(); sta.push(v); for (int i = v; i != s; i = edgeTo[i]) sta.push(edgeTo[i]); while (!sta.isEmpty()) System.out.println(sta.pop() + " "); } }
連結成分計算
package Graph; public class ConnectedComp { private Graph g; private boolean[] marked; private int count; private int[] id; public ConnectedComp(Graph g) { this.g = g; id = new int[g.V()]; marked = new boolean[g.V()]; } /** * 调用方法,便利全部结点判断分量数 */ public void DFS() { for (int s = 0; s < g.V(); s++) { if (!marked[s]) { DFS(s); count++; } } } /** * DFS算法计算连通结点 * * @param s * 起点 */ private void DFS(int s) { marked[s] = true; id[s] = count; for (int w : g.adj(s)) if (!marked[w]) DFS(w); } /** * 初始化marked标记数组状态 */ public void cleanMarked() { for (boolean b : marked) b = false; } /** * 返回该图总分量数目 * * @return 分量数 */ public int count() { return count; } /** * 返回该节点属于第几个分量 * * @param s * 判断结点 * @return 分量组数 */ public int id(int s) { return id[s]; } }
非巡回グラフ問題
package Graph; public class Cycle { private Graph g; private boolean[] marked; private boolean hasCycle; public Cycle(Graph g) { this.g = g; marked = new boolean[g.V()]; for(int s=0;s<g.V();s++) if(!marked[s]) DFS(s,s); } /** * DFS算法计算无环图问题 * * @param s * 起点 */ public void DFS(int s, int v) { marked[s] = true; for (int w : g.adj(s)) if (!marked[w]) DFS(w, s); else if (w != v) hasCycle = true; } /** * 初始化marked标记数组状态 */ public void cleanMarked() { for (boolean b : marked) b = false; } /** * 判断是否有环 * * @return 判断结果 */ public boolean hasCycle() { return hasCycle; } }
二部グラフの二色問題
りー以上がJava優先度検索(DFS/BFS)の実用化の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ホットAIツール

Undresser.AI Undress
リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover
写真から衣服を削除するオンライン AI ツール。

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

Video Face Swap
完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

人気の記事

ホットツール

メモ帳++7.3.1
使いやすく無料のコードエディター

SublimeText3 中国語版
中国語版、とても使いやすい

ゼンドスタジオ 13.0.1
強力な PHP 統合開発環境

ドリームウィーバー CS6
ビジュアル Web 開発ツール

SublimeText3 Mac版
神レベルのコード編集ソフト(SublimeText3)

ホットトピック











この記事では、Java Spring の面接で最もよく聞かれる質問とその詳細な回答をまとめました。面接を突破できるように。

Java 8は、Stream APIを導入し、データ収集を処理する強力で表現力のある方法を提供します。ただし、ストリームを使用する際の一般的な質問は次のとおりです。 従来のループにより、早期の中断やリターンが可能になりますが、StreamのForeachメソッドはこの方法を直接サポートしていません。この記事では、理由を説明し、ストリーム処理システムに早期終了を実装するための代替方法を調査します。 さらに読み取り:JavaストリームAPIの改善 ストリームを理解してください Foreachメソッドは、ストリーム内の各要素で1つの操作を実行する端末操作です。その設計意図はです

Java での日付までのタイムスタンプに関するガイド。ここでは、Java でタイムスタンプを日付に変換する方法とその概要について、例とともに説明します。

カプセルは3次元の幾何学的図形で、両端にシリンダーと半球で構成されています。カプセルの体積は、シリンダーの体積と両端に半球の体積を追加することで計算できます。このチュートリアルでは、さまざまな方法を使用して、Javaの特定のカプセルの体積を計算する方法について説明します。 カプセルボリュームフォーミュラ カプセルボリュームの式は次のとおりです。 カプセル体積=円筒形の体積2つの半球体積 で、 R:半球の半径。 H:シリンダーの高さ(半球を除く)。 例1 入力 RADIUS = 5ユニット 高さ= 10単位 出力 ボリューム= 1570.8立方ユニット 説明する 式を使用してボリュームを計算します。 ボリューム=π×R2×H(4

PHP and Python each have their own advantages, and the choice should be based on project requirements. 1.PHPは、シンプルな構文と高い実行効率を備えたWeb開発に適しています。 2。Pythonは、簡潔な構文とリッチライブラリを備えたデータサイエンスと機械学習に適しています。

PHPは、サーバー側で広く使用されているスクリプト言語で、特にWeb開発に適しています。 1.PHPは、HTMLを埋め込み、HTTP要求と応答を処理し、さまざまなデータベースをサポートできます。 2.PHPは、ダイナミックWebコンテンツ、プロセスフォームデータ、アクセスデータベースなどを生成するために使用され、強力なコミュニティサポートとオープンソースリソースを備えています。 3。PHPは解釈された言語であり、実行プロセスには語彙分析、文法分析、編集、実行が含まれます。 4.PHPは、ユーザー登録システムなどの高度なアプリケーションについてMySQLと組み合わせることができます。 5。PHPをデバッグするときは、error_reporting()やvar_dump()などの関数を使用できます。 6. PHPコードを最適化して、キャッシュメカニズムを使用し、データベースクエリを最適化し、組み込み関数を使用します。 7

Java は、初心者と経験豊富な開発者の両方が学習できる人気のあるプログラミング言語です。このチュートリアルは基本的な概念から始まり、高度なトピックに進みます。 Java Development Kit をインストールしたら、簡単な「Hello, World!」プログラムを作成してプログラミングを練習できます。コードを理解したら、コマンド プロンプトを使用してプログラムをコンパイルして実行すると、コンソールに「Hello, World!」と出力されます。 Java の学習はプログラミングの旅の始まりであり、習熟が深まるにつれて、より複雑なアプリケーションを作成できるようになります。
