I just wondering where to put this code
if(node == goal){
System.out.print("Found path: ");
for(int n : stack){
System.out.print(n + " ");
}
}
in this method:
public void performRecursiveDFS(Graph G, int node, int goal) {
Stack<Integer> stack = new Stack<Integer>();
stack.push(node);
while (!stack.isEmpty()) {
node = stack.pop();
if (!visited[node]) {
visited[node] = true;
for (int w : G.adjList(node)) {
stack.push(w);
}
}
}
}
For the reason is, I want to print the path from the start node to the goal node. For example like this, Found path: 0 1 2 3 4 7. I tried putting it after node = stack.pop() but it showed me something like this Found path: 3. Any reason/suggestion? Is there something wrong with my code? If so, please direct me in detail. Questions are welcome. Thanks in advance.
You have implemented part of the DFS that keep track of visited nodes and you can extend it to know source path also that link to next node
Full DFS implementation will look something like below that will handle paths request also
import java.util.ArrayDeque;
import java.util.Arrays;
import java.util.Collections;
import java.util.Deque;
public class DirectedDFS {
private final Digraph g;
private final int source;
private boolean[] marked;
private int[] edgeFrom;
public DirectedDFS(Digraph g, int source) {
this.g = g;
this.source = source;
init(g);
dfs(g, source);
}
private void init(Digraph g) {
this.marked = new boolean[g.V()];
this.edgeFrom = new int[g.V()];
Arrays.fill(edgeFrom, -1);
}
private void dfs(Digraph g, int source) {
marked[source] = true;
for (int vertex : g.adj(source)) {
if (!marked[vertex]) {
edgeFrom[vertex] = source;
dfs(g, vertex);
}
}
}
public boolean hasPath(int v) {
return marked[v];
}
public Iterable<Integer> path(int v) {
if (hasPath(v)) {
final Deque<Integer> paths = new ArrayDeque<>();
int vertex = v;
paths.push(v);
while ((vertex = edgeFrom[vertex]) != -1) {
paths.push(vertex);
}
return paths;
}
return (Iterable<Integer>) Collections.emptyIterator();
}
}
The stack is currently storing nodes to check next not nodes that have already been checked to get to the current point.
To get the path taken you will need to create a list and add each node that is checked to that list.
Once you get a node you can check if that node is the goal node then you can print out the list
You currently aren't storing the path to the current node so you can't print it. A fairly easy way to achieve this is to use a map to plot the path back to the origin. This can replace your use of the visited array.
Here's how it would look:
public void performRecursiveDFS(Graph G, int start, int goal) {
Stack<Integer> remaining = new Stack<Integer>();
remaining.push(start);
Map<Integer, Integer> previous = new HashMap<>();
while (!remaining .isEmpty()) {
int current = remaining.pop();
if (current == goal) {
Deque<Integer> path = new LinkedList<>();
path.addFirst(current);
while (previous.containsKey(path.peek())
path.addFirst(previous.get(path.peek()));
// print path
} else if (!previous.containsKey(current)) {
for (int w : G.adjList(current)) {
previous.put(w, current);
remaining.push(w);
}
}
}
}
Related
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 3 years ago.
Improve this question
I have a graph where its nodes are in the following structure:
Class Node:
int source;
int next;
So, I have the following nodes: [(1,2), (2,3), (3,4), (1,4)]
I wanted to list all possible paths from 1 to 3 it would list: [[(1,2),(2,3)],[(1,4),(4,3)].
I'm trying with this code, but I'm missing something:
public List<Node> getNodeNeighbors(Node n) {
List<Node> filteredNodes = new ArrayList<Node>();
List<Node> allNodes = (List<Node>) nodesRepository.findAll();
for (Node node: allNodes) {
if (node.source == n.next) {
filteredNodes.add(node);
}
}
return filteredNodes;
}
public List<Node> bfs(Node n, String destinationNodeNumber, List<Node> path) {
visitedX.add(n); //visitedX is a global List to control visited nodes
path.add(n); //local path to be listed
List<Node> neighbors = getNodeNeighbors(n); //function to get node neighbors
if (n.next.equals(destinationNodeNumber)) {
allPaths.add(paths); //all paths to be listed
path.remove(n);
}
for (Node nNode: neighbors) {
if(!visitedX.contains(nNode)) {
bfs(nNode, destinationNodeNumber, path);
}
}
return null;
}
There are many flaws in your code:
the name of your class Node is misleading: Edge would be a better name,
method getNodeNeighbors only considers one direction of each edge
what are the fields aCompany and anotherCompany? i assume you meant source and next?
what is class Contract?
destinationNodeNumber is a String; it should be an int.
the visitedX set prevents two paths from using a same edge; you just need to ensure that an edge doesn't appear more that once in a single path.
you actually implemented a DFS, not a BFS
you always add the same path to allPaths; you should make a copy instead.
Here is a class Edge:
public class Edge {
final int source;
final int next;
Edge(int source, int next) {
this.source = source;
this.next = next;
}
#Override
public String toString() {
return "(" + source + "," + next + ')';
}
}
Then the class Graph that contains the search algorithm:
public class Graph {
private final Iterable<Edge> allNodes;
public Graph(Iterable<Edge> allNodes) {
this.allNodes = allNodes;
}
public List<Edge> edgesFrom(int vertex) {
List<Edge> filteredNodes = new ArrayList<Edge>();
for (Edge node : allNodes) {
if (node.source == vertex || node.next == vertex) {
filteredNodes.add(node);
}
}
return filteredNodes;
}
public List<List<Edge>> allPaths(int source, int dest) {
List<Edge> path = new ArrayList<>();
List<List<Edge>> allPaths = new ArrayList<>();
for (Edge n: edgesFrom(source)) {
searchPaths(n, source, dest, path, allPaths);
}
return allPaths;
}
private void searchPaths(Edge n, int source, int dest, List<Edge> path,
List<List<Edge>> allPaths) {
path.add(n); //local path to be listed
int next = n.source == source ? n.next : n.source;
List<Edge> neighbors = edgesFrom(next); //function to get node neighbors
if (next == dest) {
allPaths.add(new ArrayList<>(path)); //all paths to be listed
}
for (Edge nNode : neighbors) {
if (!path.contains(nNode)) {
searchPaths(nNode, next, dest, path, allPaths);
}
}
path.remove(n);
}
}
And here is the example that uses these classes:
Graph graph = new Graph(Arrays.asList(
new Edge(1,2), new Edge(2,3), new Edge(3,4), new Edge(1,4)));
List<List<Edge>> allPaths = graph.allPaths(1,3);
for (List<Edge> path: allPaths) {
System.out.println(path);
}
I would appreciate any help...
I have 2 maze search algorithms which are DFS and BFS. The starting point is set at 0 and end point is set at 1. The nodes are placed in a stack and starts visiting its neighbors to find the path to 1. The nodes that are not involved in the path to 1 should be erased which is not happening. And also when the path finds the goal which is 1 it is not stopping.
Basically the testMaze path should be 0 5 4 1 whereas BFS is giving me 0 3 5 0 2 11 4 7 1 6 8 9 10 and
DFS is giving me 0, it initiates and it never finds anything. I think the problem might lie in either the printNode function or the visited, isVisited.
Below are the methods related to these problems. Thanks for any help in advance.
import java.util.*;
public class Maze {
public Node startingNode;
public ArrayList<Node> nodes = new ArrayList<>();
public int[][] matrix = new int[100][100];
// to set starting node at 0
public void setStartingNode(Node n) {
this.startingNode = n;
}
public Node getStartingNode() {
return this.startingNode;
}
public void addNode(int n) {
nodes.add(new Node (n));
}
public void visited(int n1) {
for(Node n2 : nodes) {
if(n2.list == n1) {
n2.visited = true;
}
}
}
public boolean isVisited(int n1) {
for(Node n2 : nodes) {
if(n2.list == n1) {
return n2.visited ;
}
}
return false;
}
public Node getNode(int n) {
for(Node n2 : nodes) {
if(n2.list == n) {
return n2;
}
}
return new Node(-1);
}
//TODO get the next unvisited node
public Node getNextNode(Node n) {
int link = n.list;
int i = 0;
while (i<nodes.size()) {
if(matrix[link][i] == 1 && isVisited(i) == false)
{
return (Node)getNode(i);
}
i++;
}
return null;
}
//algorithm uses queue and should find all paths
public void bfs() {
Queue<Node> q=new LinkedList<Node>();
q.add(this.startingNode);
printNode(this.startingNode);
startingNode.visited=true;
while(!q.isEmpty())
{
Node n=(Node)q.remove();//
Node child=null;//
while((child=getNextNode(n))!=null)
{
child.visited=true;
printNode(child);
q.add(child);
}
}
//Clear visited property of nodes
clearNodes();
}
// algorithm uses stack and should find fastest solution
public void dfs() {
Stack<Node> s=new Stack<Node>();
s.push(this.startingNode);
startingNode.visited=true;
printNode(startingNode);
while(!s.isEmpty())
{
Node n=(Node)s.peek();
Node child=getNextNode(n);
if(child!=null)
{
child.visited=true;
printNode(child);
s.push(child);
}
else
{
s.pop();
}
}
//Clear visited property of nodes
clearNodes();
}
private void clearNodes() {
int j = 0;
while (j < 0) {
Node n = (Node)nodes.get(j);
n.visited = false;
j++;
}
}
// to print nodes
private void printNode(Node n) {
System.out.print(n.list + " ");
}
}
Below is the main class
import java.util.*;
import java.io.*;
import javax.swing.*;
// C:\Users\Mannie\Desktop\maze1.txt
// C:\Users\Mannie\Desktop\maze2.txt
// C:\Users\Mannie\Desktop\maze3.txt
public class Main {
public static void main(String args[]) throws IOException {
String stringNode;
File file = new File(JOptionPane.showInputDialog("Please enter file path"));
ArrayList<String> nodes = new ArrayList<>();
Maze maze = new Maze();
maze.setStartingNode(new Node(0));
// idea is to convert string into 2D arrays here removing substring " " using .split
try {
try (Scanner sc = new Scanner(new FileInputStream(file))) {
while (sc.hasNextLine()) {
stringNode = sc.nextLine();
nodes.add(stringNode);
String[] segment = stringNode.split(" ");
//for (String val: ){
//the first time this loops the value will be 11, the second time it will be 3
//i have no idea what you
int intNode1 = Integer.parseInt(segment[0]);
int intNode2 = Integer.parseInt(segment[1]);
//System.out.println(intNode);
maze.matrix[intNode1][intNode2] = 1;
maze.matrix[intNode2][intNode1] = 1;
}
// nodes
for (int k=0;k<100;++k)
maze.nodes.add(new Node(k));
}
finally
{
}
} catch (FileNotFoundException e) {
}
Iterator<String> i = nodes.iterator();
while (i.hasNext()) {
System.out.println(i.next());
}
// To print bfs results
// also print the system clock time to time the algorithm using
// System.nanoTime();
maze.bfs();
System.nanoTime();
System.out.println();
// To print dfs results
// also print the system clock time to time the algorithm using
// System.nanoTime();
maze.dfs();
System.nanoTime();
}
}
Here is the Node class which just passes through the nodes
public class Node {
public int list;
public boolean visited = false;
public Node(int node) {
this.list = node;
}
}
In your code
public Node getNode(int n) {
for(Node n2 : nodes) {
if(n2.list == n) {
return n2;
}
}
return new Node(-1);
}
you are returning a new Node(-1); instead of null as you expect here:
while((child=getNextNode(n))!=null)
{
child.visited=true;
printNode(child);
q.add(child);
}
This causes wrong nodes to be printed and it will not stop. This code was takes from bfs() but also applies to dfs(). You should return null instead.
I'm developing a search algorithm for finding paths in a graph. In this algorithm i need to find all the paths in an undirected, not weighted graph that go trough each graph connection only once.
Currently, what my prgoram is doing, is finding all the paths that go trough each node only once. I need connections and not nodes.
Here is my code:
import java.util.*;
public class dfs {
private static Map<Integer, LinkedHashSet<Integer>> map = new HashMap<Integer, LinkedHashSet<Integer>>();
private int startNode;
private int numLinks;
public dfs(int startNode, int numLinks) {
super();
this.startNode = startNode;
this.numLinks = numLinks;
}
public int getNumLinks(){
return numLinks;
}
public void addEdge(int source, int destiny) {
LinkedHashSet<Integer> adjacente = map.get(source);
if(adjacente==null) {
adjacente = new LinkedHashSet<Integer>();
map.put(source, adjacente);
}
adjacente.add(destiny);
}
public void addLink(int source, int destiny) {
addEdge(source, destiny);
addEdge(destiny, source);
}
public LinkedList<Integer> adjacentNodes(int adj) {
LinkedHashSet<Integer> adjacente = map.get(adj);
System.out.println("adjacentes:" + adjacente);
if(adjacente==null) {
return new LinkedList<Integer>();
}
return new LinkedList<Integer>(adjacente);
}
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int numVertices = input.nextInt();
int numLinks = input.nextInt();
int startNode = input.nextInt();
int endNode = startNode;
dfs mapa = new dfs(startNode, numLinks);
for(int i = 0; i<numLinks; i++){
mapa.addLink(input.nextInt(), input.nextInt());
}
List<ArrayList<Integer>> paths = new ArrayList<ArrayList<Integer>>();
List<Integer> visited = new ArrayList<Integer>();
visited.add(startNode);
Integer currentNode = 0;
Iterator it = map.entrySet().iterator();
while (it.hasNext()) {
Map.Entry pairs = (Map.Entry)it.next();
currentNode = (Integer) pairs.getKey();
mapa.findAllPaths(mapa, visited, paths, currentNode);
}
}
private void findAllPaths(dfs mapa, List<Integer> visited,
List<ArrayList<Integer>> paths, Integer currentNode) {
if (currentNode.equals(startNode)) {
paths.add(new ArrayList<Integer>(visited));
LinkedList<Integer> nodes = mapa.adjacentNodes(currentNode);
for (Integer node : nodes) {
List<Integer> temp = new ArrayList<Integer>();
temp.addAll(visited);
temp.add(node);
System.out.println("temp:" + temp);
findAllPaths(mapa, temp, paths, node);
}
}
else {
LinkedList<Integer> nodes = mapa.adjacentNodes(currentNode);
System.out.println("currentNode:" + currentNode);
List<Integer> inseridos = new ArrayList<Integer>();
for (Integer node : nodes) {
if (visited.contains(node)) {
continue;
}
List<Integer> temp = new ArrayList<Integer>();
inseridos.add(currentNode);
temp.addAll(visited);
System.out.println("visited:" + visited);
temp.add(node);
findAllPaths(mapa, temp, paths, node);
}
}
}
}
Right now, i think the following code:
if (visited.contains(node)) {
continue;
}
is making that the program not going through each node more than once.
I need helping transforming my program to go trough each connection only once, and not through each node only once.
(I'm sorry about my english, i'm not a native)
If you're willing to do some rewriting, I think this kind of problem is more cleanly expressed in an OO fashion.
You could build a linked graph out of Node and Edge instances, allowing you to mark visited edges as you traverse the graph.
class Node
{
List<Edge> adjacentEdges;
boolean isVisited;
}
class Edge
{
Node node1;
Node node2;
boolean isVisited;
}
I have here a single linked list for a program that makes a collage. This runs perfectly but I was wondering how to make it a double linked list. I really have no idea what a double linked is though or how to create one. Any help would be appreciated...
There are 3 classes.
class LinearCollage
{
private Picture myArray[];
private class Node
{
Picture data;
Node pNext;
};
private Node pFirst;
private Node pLast;
private int nPictures;
private Picture clipboard;
public LinearCollage()
{
pFirst = null;
pLast = null;
nPictures = 0;
}
public void addPictureAtEnd(Picture aPictureReference)
{
Node temp = new Node();
temp.data = aPictureReference;
temp.pNext = null;
if( pLast == null )
{
pLast = temp;
pFirst = temp;
}
else
{
pLast.pNext = temp;
pLast = temp;
}
nPictures++;
}
public Picture makeCollage()
{
int collageHeight = 400;
int collageWidth = 400;
for( Node finger = pFirst; finger != null; finger = finger.pNext )
{
System.out.println("Process Picture " + finger.data);
}
Picture retval = new Picture(collageHeight,collageWidth);
int i = 0;
for( Node finger = pFirst; finger != null; finger = finger.pNext )
{
System.out.println("Process Picture " + finger.data);
finger.data.compose(retval, 50*i, 50*i);
i++;
}
return retval;
}
public void cutMiddle()
{
int cutIndex = nPictures-1;
clipboard = myArray[cutIndex];
for( int i = cutIndex; i < nPictures - 1; i++ )
{
myArray[i] = myArray[i + 1];
}
nPictures--;
}
public void cutEnd()
{
int cutIndex = nPictures;
clipboard = myArray[cutIndex];
for( int i = cutIndex; i<nPictures - 1; i++)
{
myArray[i] = myArray[i + 1];
}
nPictures--;
}
public void pasteEnd()
{
myArray[nPictures] = clipboard;
nPictures++;
}
public boolean isFull()
{
return false;
}
public boolean isEmpty()
{
return nPictures == 0;
}
}
import java.util.Scanner;
class LineCollageMaker
{
public static void main(String a[])
{
LinearCollage myCollage;
Scanner uiInput = new Scanner(System.in);
myCollage = new LinearCollage();
FileChooser.pickMediaPath();
boolean inputting = true;
while( inputting )
{
System.out.println("Another picture? Type Y if so.");
String answer = uiInput.next();
if(answer.equals("Y"))
{
Picture pin = new Picture(FileChooser.pickAFile());
myCollage.addPictureAtEnd(pin);
}
else
{
inputting = false;
}
}
Picture firstToShow = myCollage.makeCollage();
firstToShow.show();
//YOU Code the user inteface loop and dispatch to methods
//of myCollage here..
boolean done = false;
while( !done )
{
System.out.println("MENU (CASE SENSITIVE!)");
System.out.println("CM - cut middle and move it to the clipboard");
System.out.println("PE - paste clipboard to end");
System.out.println("CE - cut end and move it to clipboard");
System.out.println("XX - stop running this program");
String command = uiInput.next();
if(command.equals("XX"))
done = true;
else if(command.equals("CM"))
{
if(myCollage.isEmpty())
{
System.out.println("Can't cut from an empty collage.");
}
else
{
myCollage.cutMiddle();
myCollage.makeCollage().show();
}
}
else if(command.equals("PE"))
{
if(myCollage.isFull())
{
System.out.println("Can't paste to an empty collage.");
}
else
{
myCollage.pasteEnd();
myCollage.makeCollage().show();
}
}
else if(command.equals("CE"))
{
if(myCollage.isEmpty())
{
System.out.println("Can't copy from an empty collage.");
}
else
{
myCollage.cutEnd();
myCollage.makeCollage().show();
}
}
else
System.out.println("Unrecognized command. Try again.");
}
}
}
public class Node
{
//le class variables
private Picture myPic;
private Node next;
//le constructors
public Node(Picture heldPic)
{
myPic=heldPic;
next=null;
}
public void setNext(Node nextOne)
{
this.next=nextOne;
}
public Node getNext()
{
return this.next;
}
public Picture getPicture()
{
return this.myPic;
}
//le methods
public void drawFromMeOn(Picture bg)
{
Node current;
int currentX=0, currentY=bg.getHeight()-1;
current = this;
while (current != null)
{
current.drawMeOn(bg,currentX, currentY);
currentX = currentX + current.getPicture().getWidth();
current=current.getNext();
}
}
private void drawMeOn(Picture bg, int left, int bottom)
{
this.getPicture().blueScreen(bg, left, bottom-this.getPicture().getHeight());
}
}
A doubly linked list is simply a linked list where every element has both next and prev mebers, pointing at the elements before and after it, not just the one after it in a single linked list.
so to convert your list to a doubly linked list, just change your node to be:
private class Node
{
Picture data;
Node pNext;
Node pPrev;
};
and when iterating the list, on each new node add a reference to the previous node.
A doubly-linked list takes a singly-linked list one step further by also having a reference to the previous node, rather than just the next one.
I confess I am slightly confused by your code as it looks like you have a private class for Node and then another public class for it. To make this a doubly-linked list add another Node instance variable into your Node class which references the previous node, and then update this variable when you add in new nodes.
You can convert Single linked list to Double linked list via a concept called XOR based linked list. The beauty of XOR truth table makes suitable for this use case.
Check this out : https://www.geeksforgeeks.org/xor-linked-list-a-memory-efficient-doubly-linked-list-set-1/
Preface: I know that there are high quality graph APIs available. I'm interested in writing my own for self-improvement.
This is my function to add nodes:
public void addNode(Vertex v, Collection<Edge> neighbors) {
int originalSize = size();
if (head == null) {
head = v;
}
else {
Collection<Edge> inEdges = new ArrayList<Edge>();
inEdges.addAll(neighbors);
traverseGraphToAdd(head, inEdges, v);
}
assert originalSize + 1 == size() :
String.format("adding operation failed. original size: %d, current size: %d", originalSize, size());
}
private void traverseGraphToAdd(Vertex start, Collection<Edge> inEdges, Vertex toAdd) {
Iterator<Edge> iter = inEdges.iterator();
Edge e;
while (iter.hasNext()) {
e = iter.next();
if (e.getSource().equals(start)) {
start.addEdge(e);
iter.remove();
}
else if (! directionalEdges && e.getSink().equals(start)) {
start.addEdge(e);
iter.remove();
}
}
if (inEdges.size() > 0) { //otherwise there's no point in continuing to search
for (Edge arc : start.getOutEdges()) {
traverseGraphToAdd(arc.getSink(), inEdges, toAdd);
}
}
}
Size and its dependencies:
public int size() {
int count = 0;
if (head == null) {
return 0;
}
else {
count = countNodes(head);
}
clearVisited();
return count;
}
private int countNodes(Vertex start) {
int result = 1;
start.setVisited(true);
for (Edge e: start.getOutEdges()) {
if (! e.getSink().isVisited()) {
result += countNodes(e.getSink());
}
}
return result;
}
private void clearVisited() {
if (head != null) {
clearNode(head);
}
}
private void clearNode(Vertex start) {
start.setVisited(false);
for (Edge e: start.getOutEdges()) {
if (e.getSink().isVisited()) {
clearNode(e.getSink());
}
}
}
The Edge class:
public Edge(Vertex source, Vertex sink, int weight) {
this.source = source;
this.sink = sink;
this.weight = weight;
}
The following call works:
g.addNode(ftw, new HashSet<Edge>()); //first node - empty edges
g.addNode(odp, Arrays.asList(new Edge(ftw, odp, 3))); //link new node to one already in the graph
This does not:
g.addNode(tlt, Arrays.asList(new Edge(tlt, ftw, 2)));
In this one, the first argument of the Edge constructor is not the node already in the graph. I try to rectify this in addNode with the following (repeated from above):
if (e.getSource().equals(start)) { /*... */ }
else if (! directionalEdges && e.getSink().equals(start)) { /*... */ }
directionalEdges is a class field that determines whether or not this graph is directional or not.
However, this causes assertion errors:
Exception in thread "main" java.lang.AssertionError: adding operation failed. original size: 1, current size: 1
What is going on here?
The graph you're trying to create in your example looks like this:
tlt -> ftw -> odp
After creating ftw -> odp, you should (and do, I believe) have head == ftw. After adding tlt, you should have head == tlt if you want your traversal algorithm to work properly. But in the code you've shown us, there is only one place where head is assigned to, and that happens only in the condition when head == null, in the fifth line of addNode(). Therefore, head doesn't change when you add tlt, and so traverseGraphToAdd() therefore starts form ftw instead of tlt as you intend for it to.
You have a more general problem here, however, namely that your code isn't able to handle directed graphs which aren't rooted (that is, they have more than one source node.) Consider what would happen if you wanted a graph like this one:
a -> b <- c
I think you'd have a problem with this, since you no longer have a single head.