Depth First Search in Java
テキストリンク:https://www.baeldung.com/java-depth-first-search
1.概要
このチュートリアルでは、Javaでの深度優先検索について説明します.
深度優先探索(DFS)は、ツリー、図などのデータ構造に適用される遍歴アルゴリズムである.次のブランチに移動する前に、深さ優先探索は深さを優先原則として新しいブランチを探索します.
次のセクションでは、まずツリーの実装、次に図について説明します.
Javaでこれらの構造を実装する方法については、以前のツリーBinary Treeと図Graphに関するチュートリアルを参照してください.
2.ツリーの深さ優先検索
DFSを使用してツリーを巡回するには、次の3つの順序があります.先序遍歴 中序遍歴 後序は を遍歴する.
2.1先順遍歴
先行シーケンスループでは、まずそのルートノードをループし、左サブツリーと右サブツリーの順にします.
再帰を使用して、優先パスを簡単に実行します.現在のノード へのアクセス左サブツリー を巡る右サブツリー を巡る
再帰的でない方法を使用して、先行ループを実装します.ルートノードをスタック に入れるスタックが空でない場合 現在のノード(スタックトップ要素)弾スタック 現在のノード へのアクセス現在のノードの右サブノード、左サブノードを順次スタック に入れる.
2.2のシーケンス遍歴
中順ループの場合は、左サブツリーにアクセスし、ルートノードにアクセスし、最後に右サブツリーにアクセスします.
二叉探索ツリーの中順遍歴は、値の増加順にノードを遍歴することを意味する.
再帰的インプリメンテーションにおけるシーケンシャルループを使用するには、次の手順に従います.
また、再帰的でないインプリメンテーションのシーケンシャルループも使用できます.ルートノードスタック スタックが空でない場合 は、現在のノードが最も左のノード(すなわち、左のサブノードがない) になるまで、左のサブノードをスタックに押し込み続ける.現在のノード へのアクセス右サブノードスタック
2.3後序遍歴
最後に、下位ループでは、ルートノードにアクセスする前に、左サブノード、右サブノードの順にアクセスします.
前を参照して、再帰的に実装された後の順序を繰り返します.
再帰的でない実装を使用して、次の順序で巡回します.ルートノードをスタック に入れるスタックが空でない場合 左サブツリーと右サブツリー を巡回したかどうかを確認します.がない場合は、右サブノードと左サブノードをスタック に押し付ける.
3.図の深さ優先探索
図とツリーの主な違いは、図がループを含む可能性があることです.
したがって、ループ検索を回避するために、各ノードにアクセスするときにタグを付けます.
次に、図DFSの再帰的、非再帰的実装を示す.
3.1図のDFS再帰実装
まず、再帰から始めましょう.任意のノードから を開始する.現在のノードがアクセス済みであることを示す 現在のノード へのアクセスは、非アクセスの隣接ノード を巡回する.
3.2図のDFS非再帰実装
再帰を用いずに図のDFSを実現してもよい.スタックを使用して実装する必要もあります.は、任意のノードから を開始する.ノードスタック スタックが空でない場合 現在のノードがアクセス済みであることを示す 現在のノード へのアクセスアクセスされていない隣接頂点スタック
3.4トポロジのソート
図の深さ優先探索には多くの応用がある.トポロジーソートは、深度優先検索で最も有名なアプリケーションの1つです.
図面へのトポロジーソートは、その頂点の線形ソートであるため、ソースノードは各エッジに対してターゲットの前に配置されます.
トポロジーの順序付けを行うには、実装されたばかりのDFSを簡単に改造する必要があります.アクセスする頂点をスタックに保持する必要があります.トポロジーソートは、反対の順序でアクセスする頂点 であるためです.は、すべての隣接ノードを巡回した後にのみ、アクセスしたノードをスタックにプッシュします.
4.結論
本論文では,ツリーと図の深さ優先探索について論じた.
完全なコードはGitHubを参照してください.
原文:https://www.baeldung.com/java-depth-first-search 作者:baeldung訳者:陳苓洪
1.概要
このチュートリアルでは、Javaでの深度優先検索について説明します.
深度優先探索(DFS)は、ツリー、図などのデータ構造に適用される遍歴アルゴリズムである.次のブランチに移動する前に、深さ優先探索は深さを優先原則として新しいブランチを探索します.
次のセクションでは、まずツリーの実装、次に図について説明します.
Javaでこれらの構造を実装する方法については、以前のツリーBinary Treeと図Graphに関するチュートリアルを参照してください.
2.ツリーの深さ優先検索
DFSを使用してツリーを巡回するには、次の3つの順序があります.
2.1先順遍歴
先行シーケンスループでは、まずそのルートノードをループし、左サブツリーと右サブツリーの順にします.
再帰を使用して、優先パスを簡単に実行します.
public void traversePreOrder(Node node) {
if (node != null) {
visit(node.value);
traversePreOrder(node.left);
traversePreOrder(node.right);
}
}
再帰的でない方法を使用して、先行ループを実装します.
public void traversePreOrderWithoutRecursion() {
Stack<Node> stack = new Stack<Node>();
Node current = root;
stack.push(root);
while(!stack.isEmpty()) {
current = stack.pop();
visit(current.value);
if(current.right != null) {
stack.push(current.right);
}
if(current.left != null) {
stack.push(current.left);
}
}
}
2.2のシーケンス遍歴
中順ループの場合は、左サブツリーにアクセスし、ルートノードにアクセスし、最後に右サブツリーにアクセスします.
二叉探索ツリーの中順遍歴は、値の増加順にノードを遍歴することを意味する.
再帰的インプリメンテーションにおけるシーケンシャルループを使用するには、次の手順に従います.
public void traverseInOrder(Node node) {
if (node != null) {
traverseInOrder(node.left);
visit(node.value);
traverseInOrder(node.right);
}
}
また、再帰的でないインプリメンテーションのシーケンシャルループも使用できます.
public void traverseInOrderWithoutRecursion() {
Stack<Node> stack = new Stack<Node>();
Node current = root;
stack.push(root);
while(! stack.isEmpty()) {
while(current.left != null) {
current = current.left;
stack.push(current);
}
current = stack.pop();
visit(current.value);
if(current.right != null) {
current = current.right;
stack.push(current);
}
}
}
2.3後序遍歴
最後に、下位ループでは、ルートノードにアクセスする前に、左サブノード、右サブノードの順にアクセスします.
前を参照して、再帰的に実装された後の順序を繰り返します.
public void traversePostOrder(Node node) {
if (node != null) {
traversePostOrder(node.left);
traversePostOrder(node.right);
visit(node.value);
}
}
再帰的でない実装を使用して、次の順序で巡回します.
public void traversePostOrderWithoutRecursion() {
Stack<Node> stack = new Stack<Node>();
Node prev = root;
Node current = root;
stack.push(root);
while (!stack.isEmpty()) {
current = stack.peek();
boolean hasChild = (current.left != null || current.right != null);
boolean isPrevLastChild = (prev == current.right ||
(prev == current.left && current.right == null));
if (!hasChild || isPrevLastChild) {
current = stack.pop();
visit(current.value);
prev = current;
} else {
if (current.right != null) {
stack.push(current.right);
}
if (current.left != null) {
stack.push(current.left);
}
}
}
}
3.図の深さ優先探索
図とツリーの主な違いは、図がループを含む可能性があることです.
したがって、ループ検索を回避するために、各ノードにアクセスするときにタグを付けます.
次に、図DFSの再帰的、非再帰的実装を示す.
3.1図のDFS再帰実装
まず、再帰から始めましょう.
public void dfs(int start) {
boolean[] isVisited = new boolean[adjVertices.size()];
dfsRecursive(start, isVisited);
}
private void dfsRecursive(int current, boolean[] isVisited) {
isVisited[current] = true;
visit(current);
for (int dest : adjVertices.get(current)) {
if (!isVisited[dest])
dfsRecursive(dest, isVisited);
}
}
3.2図のDFS非再帰実装
再帰を用いずに図のDFSを実現してもよい.スタックを使用して実装する必要もあります.
public void dfsWithoutRecursion(int start) {
Stack<Integer> stack = new Stack<Integer>();
boolean[] isVisited = new boolean[adjVertices.size()];
stack.push(start);
while (!stack.isEmpty()) {
int current = stack.pop();
isVisited[current] = true;
visit(current);
for (int dest : adjVertices.get(current)) {
if (!isVisited[dest])
stack.push(dest);
}
}
}
3.4トポロジのソート
図の深さ優先探索には多くの応用がある.トポロジーソートは、深度優先検索で最も有名なアプリケーションの1つです.
図面へのトポロジーソートは、その頂点の線形ソートであるため、ソースノードは各エッジに対してターゲットの前に配置されます.
トポロジーの順序付けを行うには、実装されたばかりのDFSを簡単に改造する必要があります.
public List<Integer> topologicalSort(int start) {
LinkedList<Integer> result = new LinkedList<Integer>();
boolean[] isVisited = new boolean[adjVertices.size()];
topologicalSortRecursive(start, isVisited, result);
return result;
}
private void topologicalSortRecursive(int current, boolean[] isVisited, LinkedList<Integer> result) {
isVisited[current] = true;
for (int dest : adjVertices.get(current)) {
if (!isVisited[dest])
topologicalSortRecursive(dest, isVisited, result);
}
result.addFirst(current);
}
4.結論
本論文では,ツリーと図の深さ優先探索について論じた.
完全なコードはGitHubを参照してください.
原文:https://www.baeldung.com/java-depth-first-search 作者:baeldung訳者:陳苓洪