在Java中查找包含循环的图中一定距离内的所有边
我有一个由在Java中查找包含循环的图中一定距离内的所有边,java,algorithm,search,graph,priority-queue,Java,Algorithm,Search,Graph,Priority Queue,我有一个由Edge对象连接的Node对象图,需要通过以下方式进行探索: 我得到一个起始边源,需要找到所有其他边对象,以便沿路径传递的边的长度总和不超过最大范围,并在满足条件的每个边执行一些操作 我对这个问题的解决方案是递归地进行分支,在我移动时跟踪移动距离(Edge#getEdgeConnections()返回一个ArrayList,其中包含连接到调用的Edge的所有Edge对象): 现在,我想到的解决方案是做一个不同的搜索模式,在那里我会有一个“边界”边的列表(或地图),并按照增加距离的顺序探
Edge
对象连接的Node
对象图,需要通过以下方式进行探索:
我得到一个起始边源
,需要找到所有其他边
对象,以便沿路径传递的边的长度总和不超过最大范围
,并在满足条件的每个边
执行一些操作
我对这个问题的解决方案是递归地进行分支,在我移动时跟踪移动距离(Edge#getEdgeConnections()
返回一个ArrayList
,其中包含连接到调用的Edge
的所有Edge
对象):
现在,我想到的解决方案是做一个不同的搜索模式,在那里我会有一个“边界”边的列表(或地图),并按照增加距离的顺序探索它们(每次探索一条边时都会向这个边界添加新边)
可能会涉及到大量的边,因此我不希望每次都遍历整个列表,以找到距离源最短的边
是否有某种类型的集合能够以这种方式自动保持订单,并且能够有效地添加/删除元素
SortedMap是我要找的吗?在这种情况下,我将如何使用它
编辑:
感谢所有响应者。最后,我使用了一个带有包装类的
PriorityQueue
(有关详细信息和代码,请参见)。您可以使用对BFS或DFS的修改,其中还为路径的最大长度添加了一个额外规则(除了检查是否访问了所有邻居节点)
我建议你选择DFS,因为它有点接近你目前正在做的事情。您也可以用任何一种方法轻松地“放入”doSomethingToEdge,而不是使用其他数据结构,我建议您调整算法:
您已经实现了某种方法来遍历图形。如果您使用某种类型的替换,您可以在到达指定范围并访问了范围内的每条边一次后停止(通过使用您已经实现的isOccupied逻辑)。注意:写下答案后,我意识到您是在谈论边,但我在节点方面提到的相同示例和相同理论也适用于边。 如果只执行BFS,它将不起作用,因为您会将
节点
标记为过早访问。考虑这个例子
最大范围为20&d(x,y)
表示x
和y
A->(10)E->D(10)->(5)F // d(A,E)=d(E,D)=10 & d(D,F)=5
A->(5)B->(5)C->(5)D->(5)F //d(A,B)=d(B,C)=d(C,D)=d(D,F)=5
在这种情况下,您将首先到达路径(a->E->D)
中的D(因为它更接近此路径中的a),然后将D
标记为已访问。这实际上是错误的,因为将D标记为已访问会阻止您访问F
,如果您的路径是(A->B->C->D->F)
,您本可以这样做
因此,为了避免重复并解决此问题,对于要添加的每个节点,还应添加在当前路径中看到的节点列表。这样,您仍然可以访问F
,因为当您在路径(A->B->C->D)
中到达D
时,您将看到它未被访问,因为它没有出现在您的路径中
说到实施,我将给您一个大致的想法:
创建一个包装类
NodeWrapper{
Node node;
List<Node> Parents;
int pathSum;
}
NodeWrapper{
节点;
列出家长名单;
int路径和;
}
您的BFS应如下所示:
{
Queue<NodeWrapper> queue = new LinkedList<>();
Queue.add(new NodeWrapper(sourceNode,new ArrayList<Node>));
while(!queue.isEmpty()){
NodeWrapper temp = queue.poll();
Node presentNode = temp.getNode();
List<Node> parentsList = temp.getParentsList();
for all neighbours of presentNode
if neighbour is not in presentNode && (pathSum +currentEdgeWeight )< max && your conditions
add currentNode to parent list
queue.add(new NodeWrapper(neighbour,parentList,(pathSum +currentEdgeWeight)));
}
}
{
Queue Queue=new LinkedList();
add(新的NodeWrapper(sourceNode,newarraylist));
而(!queue.isEmpty()){
NodeWrapper temp=queue.poll();
Node presentNode=temp.getNode();
List parentsList=temp.getParentsList();
对于presentNode的所有邻居
如果邻居不在presentNode&(pathSum+CurrentEdgeWight)
您正在寻找的算法是一种改进的算法,它不是搜索从a到B的最短路径,而是搜索所有短于X的最短路径。Dijkstra保证您将按照距离起点的递增顺序访问每个节点,并通过距离起点的最短路径。此外,如果没有负长度边,那么父级关系将永远不会改变——并且可以保证内部if
将沿着节点的最小路径对每条边执行一次且仅执行一次。但是,由于“比X更近的节点”集仅在末端已知(=最终距离<最大值的节点),因此您可以等待算法完成doStuffAtBranch
,仅适用于实际通向某个有趣地方的分支
伪代码如下所示:
final HashMap<Node, Double> distances = new HashMap<>();
HashMap<Node, Node> parents = new HashMap<>();
distances.put(start, 0); // start is at distance 0 from start
PriorityQueue<Vertex> q = new PriorityQueue(allVertices.size(),
new Comparator<Vertex>() {
public int compare(Vertex a, Vertex b) {
return distances.get(a) - distances.get(b);
}
});
for (Vertex v : allVertices) {
q.add(v, distances.contains(v) ?
distances.get(v) : Double.POSITIVE_INFINITY);
}
while ( ! q.isEmpty()) {
Vertex u = q.poll(); // extract closest
double current = distances.get(u);
if (current > max) {
// all nodes that are reachable in < max have been found
break;
}
for (Edge e : u.getEdges()) {
Vertex v = u.getNeighbor(e);
double alt = current + e.length();
if (alt < distances.get(v)) {
q.remove(v); // remove before updating distance
distances.put(v, alt);
parents.put(v, u); // v will now be reached via u
q.add(v); // re-add with updated distance
// if there are no negative-weight edges, e will never be re-visited
}
}
}
final HashMap distance=new HashMap();
HashMap parents=newhashmap();
距离。放置(开始,0);//起点距离起点0
PriorityQueue q=新建PriorityQueue(allVertices.size(),
新比较器(){
公共整数比较(顶点a、顶点b){
返回距离。get(a)-距离。get(b);
}
});
对于(顶点v:所有顶点){
q、 添加(v,距离。是否包含(v)?
距离。get(v):双正_无穷大);
}
而(!q.isEmpty()){
顶点u=q.poll();//提取最近的
双电流=距离。获取(u);
如果(当前>最大值){
//已找到 {
Queue<NodeWrapper> queue = new LinkedList<>();
Queue.add(new NodeWrapper(sourceNode,new ArrayList<Node>));
while(!queue.isEmpty()){
NodeWrapper temp = queue.poll();
Node presentNode = temp.getNode();
List<Node> parentsList = temp.getParentsList();
for all neighbours of presentNode
if neighbour is not in presentNode && (pathSum +currentEdgeWeight )< max && your conditions
add currentNode to parent list
queue.add(new NodeWrapper(neighbour,parentList,(pathSum +currentEdgeWeight)));
}
}
final HashMap<Node, Double> distances = new HashMap<>();
HashMap<Node, Node> parents = new HashMap<>();
distances.put(start, 0); // start is at distance 0 from start
PriorityQueue<Vertex> q = new PriorityQueue(allVertices.size(),
new Comparator<Vertex>() {
public int compare(Vertex a, Vertex b) {
return distances.get(a) - distances.get(b);
}
});
for (Vertex v : allVertices) {
q.add(v, distances.contains(v) ?
distances.get(v) : Double.POSITIVE_INFINITY);
}
while ( ! q.isEmpty()) {
Vertex u = q.poll(); // extract closest
double current = distances.get(u);
if (current > max) {
// all nodes that are reachable in < max have been found
break;
}
for (Edge e : u.getEdges()) {
Vertex v = u.getNeighbor(e);
double alt = current + e.length();
if (alt < distances.get(v)) {
q.remove(v); // remove before updating distance
distances.put(v, alt);
parents.put(v, u); // v will now be reached via u
q.add(v); // re-add with updated distance
// if there are no negative-weight edges, e will never be re-visited
}
}
}
public ArrayList<Edge> uniqueEdgesWithinRange(double range) {
ArrayList<Edge> edgeList = new ArrayList<>();
PriorityQueue<ComparableEdge> frontier = new PriorityQueue<>();
frontier.add(new ComparableEdge(0.0, this));
while(!frontier.isEmpty()) {
ComparableEdge cEdge = frontier.poll();
edgeList.add(cEdge.edge);
if (cEdge.distance < range) {
for (Edge connection : cEdge.edge.getEdgeConnections()) {
if (!edgeList.contains(connection)) {
frontier.add(new ComparableEdge(cEdge.distance + connection.getLength(), connection));
}
}
}
}
return edgeList;
}
private class ComparableEdge implements Comparable<ComparableEdge> {
private double distance; // Distance from closest point on source to furthest point on edge
private Edge edge;
private ComparableEdge(double distance, Edge edge) {
this.distance = distance;
this.edge = edge;
}
@Override
public int compareTo(ComparableEdge another) {
return Double.compare(distance, another.distance);
}
}
public List<Integer> findMinDistantNodesUsingBF(int[][] graph, int startNode, int distance) {
int len = graph.length;
boolean[] processed = new boolean[len];
int[] distanceArr = new int[len];
LinkedList<Integer> queue = new LinkedList<Integer>();
List<Integer> result = new ArrayList<Integer>();
queue.add(startNode);
processed[startNode] = true;
distanceArr[startNode] = 0;
while (!queue.isEmpty()) {
int node = queue.remove();
for (int i = 0; i < len; i++) {
if (graph[node][i] == 1 && !processed[i]) {
if (distanceArr[node] == distance - 1) {
result.add(i);
} else {
queue.add(i);
distanceArr[i] = distanceArr[node] + 1;
}
processed[i] = true;
}
}
}
return result;
}
// Finds all nodes that are maximum x distance away from given node.
public Set<Integer> findMaxDistantNodesRecurse(int[][] graph, int startNode, int distance) {
int len = graph.length;
Set<Integer> set = new HashSet<Integer>();
for (int j = 0; j < len; j++) {
if (startNode == j)
continue;
if (graph[startNode][j] == 1) {
set.add(j);
if (distance > 1)
set.addAll(findMaxDistantNodesRecurse(graph, j, distance - 1));
}
}
return set;
}