假设我有一个T类型的对象,其中一个字段带有一个ArrayList,它包含我将调用list的类型为T的对象。我还有另一个类型为T的对象,我称之为目标。我想找到目标。为此,我想首先遍历列表以查看目标是否存在。如果是,我想返回原始对象。如果不是,那么我想通过列表逐个对象,并检查每个列表的目标(如果找到则返回对象)。我希望以递归方式继续此搜索,直到找到匹配项。
我无法弄清楚如何实现这一目标。我能想到的两个选项是while循环和递归。但是,当我检查各种列表时,我必须在各级之间振荡,我无法弄清楚如何做到这一点。
我的另一个想法是,我想做的事情与树的水平顺序横向相同。但是,到目前为止,我只学习了二叉树,如果可以在不遍历整个树的情况下进行水平顺序遍历,我不知道如何或者是否可以将它转换为树。
下面,查看我到目前为止编写的代码。这只会检查第一个列表是否匹配,而不是更深入,这就是我需要的。
/**
* Searches for the shortest path between start and end points in the graph.
* @param start
* @param end
* @return a list of data, starting with start and ending with end, that gives the path through
* the graph, or null if no such path is found.
*/
public List<T> shortestPath(T startLabel, T endLabel){
List<T> list = new ArrayList<>();
list.add(startLabel);
while(true){
List<T> successors = successorList(startLabel);
if (containsMatch(successors, endLabel)) {
findMatch(successors, endLabel);
}
}
}
这种情况有意义吗?如果是这样,有什么想法?它甚至可能吗? (我试过搜索,但我的所有查询都没有用)
提前感谢您的帮助。干杯!
答案 0 :(得分:1)
T听起来像是一棵树,但这只是对于其ArrayList中的每个T(以及每个ArrayLists中的每个T等),所有T都是唯一的。否则,当它不时,就像树一样遍历它可能会导致无限循环。
我不明白你的意思&#34;如果可以在不穿越整棵树的情况下进行水平顺序遍历&#34;。如果您的树T没有秩序感,那么将必须遍历整个树,因为目标T可能在任何地方。这正是你想要做的,不是吗?
将此问题视为两个相互递归的函数可能在概念上有所帮助。一个函数可以称为SearchT,另一个函数可以称为SearchArrayListT。 SearchT检查T是否是&#34;目标&#34; T.如果没有,它在T的ArrayList字段上调用SearchArrayListT。
如果传入的ArrayList为空,则SearchArrayListT产生&#34; false&#34; (即你表示没有找到目标的事实。)否则,SearchArrayListT在ArrayList的每个元素上调用SearchT,在每个元素之后检查是否&#34; true&#34;返回(或者您表示找到目标的事实)。这实际上是深度优先搜索,但您应该得到相同的结果。您可以看到如何在维基百科页面上为他们进行广度优先搜索:https://en.wikipedia.org/wiki/Breadth-first_search
特别针对您的问题,看起来您正在寻找&#34; root&#34;的路径。进入&#34;目标&#34; T,所以在这种相互递归期间,你想要通过迄今为止的路径,然后追加到目前为止的路径#34;沿着递归。更具体地说,SearchT将在pathSoFar中追加take,然后使用附加了&#34; T&#34;的pathSoFar调用SearchArrayListT。 SearchT也作为一个论点。像这样:
SearchT(T t, List<T> pathSoFar) //append t to pathSoFar, check if
//t is the goal; if it is not call SearchArrayListT(t.list, pathSoFar.add(t));
SearchArrayListT(ArrayList<T>, List<T> pathSoFar)
答案 1 :(得分:0)
如果您尝试递归查找图表中的项目,可以使用depth first search。
在遍历期间,您需要标记访问过的节点,这样您就不会在循环中继续访问它们。只有在尚未访问过节点的情况下,您才会访问节点的子节点。
这是一个使用DFS的简单Java实现,它以递归方式在树中搜索树中的值,然后在找到时捕获该节点。
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class TreeSearch<T> {
private final Set<T> marked = new HashSet<>();
private boolean found;
private Node<T> foundNode;
public TreeSearch(Node<T> node, T s) {
dfs(node, s);
}
private void dfs(Node<T> node, T s) {
if(node.value.equals(s)) {
found = true;
foundNode = node;
}
marked.add(node.value);
if(node.children != null) {
for (Node<T> child : node.children) {
if (!marked.contains(child.value)) {
dfs(child, s);
}
}
}
}
public boolean isFound() {
return found;
}
public Node<T> getFoundNode() {
return foundNode;
}
public static void main(String[] args) {
Node<Integer> root = new Node<>(0);
Node<Integer> n1 = new Node<>(1);
Node<Integer> n2 = new Node<>(2);
root.add(n1);
root.add(n2);
n2.add(n1);
Node<Integer> n3 = new Node<>(3);
n2.add(n3);
TreeSearch<Integer> search = new TreeSearch<>(root, 3);
assert search.isFound();
System.out.println(search.isFound()); // Expects true
System.out.println(search.getFoundNode());
TreeSearch<Integer> searchFail = new TreeSearch<>(root, 4);
assert !searchFail.isFound();
System.out.println(searchFail.isFound()); // Expects false
}
}
class Node<T> {
T value;
List<Node<T>> children;
public Node(T value) {
this.value = value;
}
public void add(Node<T> child) {
if(children == null) {
children = new ArrayList<>();
}
children.add(child);
}
@Override
public String toString() {
return "Node{" +
"value=" + value +
", children=" + children +
'}';
}
}
如果你运行这个类(它只有一个main方法用于测试目的),你会看到这个输出:
true
Node{value=3, children=null}
false
此算法不会告诉您最短路径。它只会告诉您,如果值在图表中以及在哪个节点中。
如果您尝试在有向图中找到源节点的最短路径,请更好地使用Breadth-first search。