Adding to a stack from a map - java

I am working on a project for school that requires us to find the shortest path between two points. Basically I use a breadth first search to traverse the graph and then use a map to keep track of each cities predecessor. My idea is then that when I reach the end I will then use the edges map to find out how a city was gotten to and essentially work backwards. However when I attempt to pull values from the map all I get is null, even though when I print out the contents it shows that there is something there. If somebody could help me track down the problem I would appreciate it.
Contents of input file with each city and its neighbor:
basic
Bismark Fargo
Minneapolis Chicago
StPaul Chicago
Minneapolis StPaul
Minneapolis Fargo
Fargo GrandForks
The code (corrected version, so this code won't exhibit the described problem any more):
import java.util.*;
import java.io.*;
public class BFSBasics {
public static void main(String[] args) throws FileNotFoundException {
Map<String, List<String>> graph = new HashMap<>();
openFile(graph, args[0]);
String start = args[1];
String end = args[2];
BFS(graph, start, end);
}
public static void openFile(Map<String,List<String>> graph,
String file)
throws FileNotFoundException{
Map<String,List<String>> aGraph = new HashMap<>();
try (Scanner scan = new Scanner(new File(file))){
if(!scan.next().equals("basic")){
System.err.println("File cannot be read.");
System.exit(1);
}else{
while(scan.hasNext()){
String city1 = scan.next();
String city2 = scan.next();
addEdge(graph, city1, city2);
addEdge(graph, city2, city1);
}
}
}
}
private static void addEdge(Map<String, List<String>> graph, String city1,
String city2){
List<String> adjacent = graph.get(city1);
if(adjacent == null){
adjacent = new ArrayList<>();
graph.put(city1, adjacent);
}
adjacent.add(city2);
}
public static void BFS(Map<String, List<String>> graph, String start,
String end) {
boolean done = false;
//cities that still need to be worked on
Queue<String> work = new ArrayDeque<>();
//cities that have already been seen
Set<String> seen = new HashSet<>();
//cities predecessor i.e. how it was gotten to
Map<String, String> edges = new HashMap<>();
LinkedList<String> path = new LinkedList<>();
String city = start;
work.add(start);
while (!done && !work.isEmpty()) {
city = work.remove();
for (String s : graph.get(city)) {
if (!seen.contains(s)) {
edges.put(s, city);
work.add(s);
seen.add(s);
if (s.equals(end)) {
done = true;
}
}
}
}
//Work backwards through the edges map and push onto the path stack
path.push(end);
String temp = edges.get(end);
while(!temp.equals(start)){
path.push(temp);
temp = edges.get(path.peek()};
}
path.push(start);
//print out the path
while(!path.isEmpty()){
System.out.println(path.pop());
}
}
}

There is something wrong with your path building code:
path.push(end); // push node (n - 1)
String temp = edges.get(end); // temp = node (n - 2)
while(!temp.equals(start)){
path.push(edges.get(temp)); // push node (n - 3) down to and including node 0
temp = path.peek(); // temp = node (n - 3) down to and including node 0
}
path.push(start); // push node 0
So the node (n - 2) will never be pushed to the path, whereas the node 0 will be pushed twice.
But except for this, the program works for me. So perheaps you really have an unreachable target, as Hbcdev suggests. You should check whether or not you actually reached the end node. Note that your graph datra structure models a directed graph, so if you want to interpret your input as undirected edges, you'll have to insert two directed edges for each line of input.
Also note that you don't mark the initial node as seen, whereas all other nodes will get marked as seen when you add them to the queue. You should mark the first as well.
Edit:
After you pasted your (almost) complete code, I fixed it in the following ways:
added two wildcard imports, for java.util.* and java.io.*. Wildcard imports are quick and dirty.
Added a closing } at the very end to close the class definition.
Added a line with the word basic to your input data. You really should System.exit(1) in case of that keyword missing, instead of continuing with inconsistent state.
With those modifications, I tested all possible combinations of two cities, always in both orders, and including paths form a city to itself. No evidence of null values anywhere, neither in output nor as a cause of printed exceptions.

I see a couple of possible problems here. The immediate cause may be this: Your logic implicitly assumes that there is only one way to reach any given node. While this may be true, I doubt it. If there are two ways to reach the same node, you overwrite the first with the second in your map.
For example, suppose the input was:
A->B
C->B
B->E
D->E
You want to get from A to E. It could be done by going A, B, E. But when you build your map, you'll create an edge entry for B, A. Then you'll write B, C, overwriting B, A. Then you write E, B. Fine. Then you write E, D, overwriting E, B. So when you're done, all that's in the edge map is (B, C) and (E, D). You then try to walk backwards from E. You find E, D. But this is wrong: you wanted E, B, but that got overwritten. When you try to find an entry for D, there is none, so it's impossible to get back to A.
A second problem is that you said that the goal was to find the SHORTEST path from start to end. But you're doing nothing to find the shortest path: you stop looking once you find any path. You really need to, in principle, find all possible paths and then select the shortest from that list. (Or hopefully, eliminate longer paths as you go, one way or another.)

Related

Removing an input from a recursive method

Good morning! I received a problem statement to write a method that returns all possible combinations of a String input passed, e.g.
if ABC is passed then it returns [A, AB, BC, ABC, AC, B, C]
if ABCD is passed then it returns [A, AB, BC, CD, ABC, AC, ACD, B, BCD, BD, ABD, AD, C, D, ABCD]
means AB and BA are always taken same, ABC, BAC and ACB are also same.
I ended up writing below code and it seems to working though (not sure).
public static Set<String> getAnyPermutations(String s,String strInput) {
Set<String> resultSet = new HashSet<>();
char[] inp = strInput.toCharArray();
for(int i=0; i<inp.length; i++) {
String temp =s+String.valueOf(inp[i]);
resultSet.add(temp);
if(i+1<=inp.length)
resultSet.addAll(getAnyPermutations(temp, String.valueOf(Arrays.copyOfRange(inp, i+1, inp.length))));
}
return resultSet;
}
My question is, I want to remove the first param(String s) from the method as using it for interal comutations only, or if that is not possible then making sure that user always pass a "" value or I can reset it to "" for the first(non-recursive) call of this method. I am going confused how to do that inside a recursive funtion.
Also please add comment if you have doubt it can fail other than this situation.
Conditions, All has to be done inside this function only, no other method can be created.
All has to be done inside this function only, no other function can be created.
Then you can't do it. The function has no (reasonable)* way of knowing whether it called itself or was called by another function.
There are lots of solutions involving creating another function. One that might fit your requirements, depending on how they're actually expressed, would be to have the function define a lambda to do the work, and have the lambda call itself. E.g., getAnyPermutations wouldn't actually be recursive, it would contain a recursive function.
But that may be out of bounds depending on the exact meaning of the quote above, since the lambda is another function, just not one that can be accessed from the outside.
* The unreasonable way is by examining a stack trace, which you can get from Thread.currentThread().getStackTrace.
You can always transform a recursive method into its iterative equivalent - e.g. see
Way to go from recursion to iteration.
In the iterative version it's easy to not expose the state parameter (you now just need to initialize it at the beginning of the iterative method).
This is not very practical in general (but I believe that the purpose of the question is more theoretical, otherwise it's always a good solution to just expose another method).
Furthermore, in this particular situation you might consider this simple iterative approach (though it is not obtained by directly translating the given code):
public static Set<String> getAnyPermutations(String strInput) {
Set<String> resultSet = new HashSet<>();
char[] inp = strInput.toCharArray();
for (int bitMask = 0; bitMask < (1 << inp.length); bitMask++) {
StringBuilder str = new StringBuilder();
for (int i = 0; i < inp.length; i++) {
if ((bitMask & (1 << i)) != 0) {
str.append(inp[i]);
}
}
if (str.length() > 0) {
resultSet.add(str.toString());
}
}
return resultSet;
}
You can change the current method to be a private one and interface it with a public method with one argument e.g.:
private static Set<String> getAnyPermutations(String s,String strInput) {
Set<String> resultSet = new HashSet<>();
char[] inp = strInput.toCharArray();
for(int i=0; i<inp.length; i++){
String temp =s+String.valueOf(inp[i]);
resultSet.add(temp);
if(i+1<=inp.length)
resultSet.addAll(getAnyPermutations(temp, String.valueOf(Arrays.copyOfRange(inp, i+1, inp.length))));
}
return resultSet;
}
Now, you can expose a one argument method to the user which in turn will call the above method, e.g.:
public static Set<String> getAnyPermutations(String strInput) {
return getAnyPermutations("", strInput);
}
Update
If you can't create any other method at all then the only alternative would be to use var-args. However, that requires change in the implementation and doesn't actually restrict the user from passing multiple values.
You can rewrite this particular algorithm so that it doesn't need to carry a state through to the recursively called invocation.
(Java-centric pseudocode):
Set<String> getAnyPermutations(String str) {
if(str.length() == 0) {
return Collections.emptySet();
}
String head = str.substring(0,1);
String tail = str.substring(1);
Set<String> permutationsOfTail = getAnyPermutations(tail);
Set<String> result = new HashSet();
// Head on its own
// For input 'ABC', adds 'A'
result.add(head);
// All permutations that do not contain head
// For input 'ABC', adds 'B', 'C', 'BC'
result.addAll(permutationsOfTail);
// All permutations that contain head along with some other elements
// For input 'ABC', adds 'AB, 'AC', 'ABC'
for(String tailPerm : permutationsOfTail) {
result.add(head + tailPerm);
}
return result;
}
This meets your aim of not creating any extra methods -- but note that it would be cleaner code if the for loop was extracted into a new method Set<String> prefixEachMember(String prefix, Set<String> strings) allowing result.addAll(prefixEachMember(head,permutationsOfTail)).
However it's not always possible to do this, and sometimes you do want to carry state. One way is the way you've asked to avoid, but I'm going to include it in my answer because it's a clean and common way of achieving the aim.
public Foo myMethod(Bar input) {
return myMethod(new HashSet<Baz>(), input);
}
private Foo myMethod(Set<Baz> state, Bar input) {
if(...) {
return ...;
} else {
...
return myMethod(..., ...);
}
}
Here, the first method is your public API, in which the collector/state parameter is not required. The second method is a private worker method, which you initially call with an empty state object.
Another option is to refer to an object field. I would recommend against this, however, because it gets confusing when recursive code refers to a global object.

Recursion to print all paths in a matrix

I came across a solution HERE. Can someone please explain how is this working. In particular, one of things that I am not able to understand is the recursive call. In one of them new ArrayList<>(path) is passed while in other simply path is passed. Why ? Between the solution is working all right.
public class Main {
public static void getPaths(int[][]A, int i, int j, ArrayList<Integer> path, ArrayList<ArrayList<Integer>> allPaths) {
int n = A.length;
if (i>=n || j>=n) return;
path.add(A[i][j]);
if (i==n-1 && j==n-1) {
allPaths.add(path);
return;
}
getPaths(A, i, j+1, new ArrayList<>(path), allPaths);
getPaths(A, i+1, j, path, allPaths);
}
public static void main(String[] args) {
ArrayList<ArrayList<Integer>> allPaths = new ArrayList<>();
getPaths(new int[][] { {1,2,3},{4,5,6},{7,8,9}}, 0,0, new ArrayList<Integer>(), allPaths );
System.out.println(allPaths);
}
}
A copy of the path so far is created and passed in the first recursive call so that further entries can be added to the path. We do not need to pass it in the second call as whatever entries will be added as a result of second call are part of the first call's path.
They represent two different paths from the current one. So, new ArrayList<>(path) is used to create a copy of the current path in one direction and just path is passed to complete the current path on the other direction.
Essentially because you want to complete two different pahts, you can't use the current one to insert two different paths in the same array. So you pass the copy in one of the calls, to have that path in a different memory area so both paths that separate on the current point can be calculated independently.

How can I continue adding nodes in my linked list with a while loop?

I'm currently learning linked list and I have discovered the basics of coding it and I fully understand them. However, I have a certain amount of nodes preset, so the user would not be able to add more. How would one implement a while loop to keep cycling through and asking the user if they want to add another piece of data.
Here is the code that I already have so far:
public class List {
public int x;
public List ptr = null;
}
Above is the object class for List. List contains a data type of x and a pointer.
import javax.swing.JOptionPane;
public class Main {
public static void main(String[] args) {
List front = new List();
front.x = Integer.parseInt(JOptionPane.showInputDialog("Enter a value"));
List l1 = new List();
l1.x = Integer.parseInt(JOptionPane.showInputDialog("Enter a value"));
List l2 = new List();
l2.x = Integer.parseInt(JOptionPane.showInputDialog("Enter a value"));
front.ptr = l1;
l1.ptr = l2;
printNodes(front);
}
public static void printNodes(List p) {
while (p != null) {
System.out.print(p.x + " ");
p = p.ptr;
}
}
}
As you can see, I have 3 Nodes created, but you cannot add anymore. I'd like to have something along the lines of:
boolean goAgain = true;
while (goAgain) {
//create a new node
String again = JOptionPane.showInputDialog("Add another node?");
if (!again.equalsIgnoreCase("yes")) {
goAgain = false;
}
}
Thank you!
P.S - I am a sophomore in high school, please use vocabulary that I will be able to understand. I wouldn't say I'm a java noob, but I'm no expert either.
Well I'd clean up your while loop to include everything in one statement. But that's just because I'm lazy. ;)
while (!JOptionPane.showInputDialog("Add another node?").equalsIgnoreCase("yes"))
{
//make a new node
}
As for the code to make a new node I would suggest implementing your List class from the List interface that Java has. You can read about it here. If you're just starting out in Java though it might be a little hard to understand. As a comment on your existing code here:
List front = new List();
front.x = Integer.parseInt(JOptionPane.showInputDialog("Enter a value"));
You're not exactly making a new node per-say, you're just creating new instances of your List class. In this case the object is labeled 'front' My suggestion is to read up more on how a List is meant to function. Here is a good example.

Make Logic in Function Recursive

Background: Imagine I have a little Robot. I place this Robot at some Node in a Map (Graph). The Robot can call the giveMeMapCopy() method to get a copy of the whole map that he is sat in. I want to give my little Robot a function by which he can use a breadth first traversal to find the shortest path to the Exit node. Here is an example of such a map:
I have watched videos on YouTube on how to do a breadth first traversal of a graph, so I have a good idea of what needs to be done. The problem is, I am finding it hard to make my logic recursive. Here is my code:
public class Robot
{
// fields required for traversal
private Queue<ArrayList<String>> queue;
private ArrayList<ArrayList<String>> result;
private String workingNode;
private ArrayList<String> routeSoFar;
private Queue<String> knownShortestPath;
public Robot() {
queue = new LinkedList<ArrayList<String>>();
result = new ArrayList<ArrayList<String>>();
routeSoFar = new ArrayList<String>();
knownShortestPath = new LinkedList<String>();
}
// Runs when Robot has reached a node.
public void enterNodeActions() {
knownShortestPath = determineIdealPath();
}
// Runs to determine where to go next
public String chooseNextNode() {
if(!knownShortestPath.isEmpty())
{
// TODO: Need to go through the
}
}
public LinkedList<String> determineIdealPath()
{
try {
// Get the map
Map m = giveMeMapCopy();
// Get all entry nodes of map
Set<String> entryNodes = m.getEntryNodes();
/*
* Loop through all Entry nodes, and find out where we are.
* Set that as current working node.
*/
for (String n : entryNodes) {
if(n == getMyLocation())
{
workingNode = n;
}
}
// All enighbours of working node.
Set<String> neighboursNames = getNeighboursNames(workingNode);
/*
* For each neighbour, construct a path from working node to the neighbour node
* And add path to Queue and Result (if not already present).
*/
for(String node : neighboursNames)
{
if(!node.equals(getMyLocation()))
{
ArrayList<String> route = new ArrayList<String>();
route.add(getMyLocation());
route.add(node);
if(!containsRoute(result, route))
{
if(!containsRoute(queue, route))
{
queue.add(route);
}
result.add(route);
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
Where I want the recursion to happen is after I have gone through all neighbours of the Entry node [ A ], I want to move to the next [ B ] and do the same for that, i.e. go through each of its neighbours (ignoring A, cause it is already present in Result list) and add them to the Queue and Result lists.
I hope the problem is clear, if not please let me know, and I'll try to clarify anything is not clear.
Breadth-first search is typically done without recursion as it is based on a queue (of partial path in your case). Depth-first search on the other hand is based on a stack, wich can be implemented quite naturally using the call-stack of a recursive function.
Essentially, what you want is to implement Dijkstra's algorithm or something similar to find the shortest path between a source and destination in a graph.
You can find such implementation in Java here. Just set all the weights at 1.

ArrayList returns same element for every index

I suspect that the value being returned is the last one I have added to my arraylist.
I've got a class Game where the following function gets executed...
public List<M> compute() throws CloneNotSupportedException{
G chil = (G) this.clone();
List<Move> Pm = new ArrayList<M>();
Point p;
for(/*condition*/){
//p is defined up here.basically loops through all possible values of p.
M m = pud.genM(chil, p);
Pm.add(m);
}
return Pmoves;
}
The strange thing is I'm doing a print on the values being returned for m and they are as expected (different) but when I loop through the List that has been created each and every element is equal to the last element that was added. It appears that this last to be added element is overriding all previous children...
The variable pud is of type User. The function being called is...
public M genM(GameState g, boardPoint p){
M m; // a move
for(/*condition*/){
m = new M(/*parameters*/);
return m;
}
return null;
}
I've simplified this class down a fair bit, there's some if else conditions and an additional for loop but I took them out of this example because they're kind of messy and most likely irrelevant.
The object M is defined as...
public M(String type, Point fPos, Point tPos, String input, G g){
this.type = type;
this.toPos = toPos;
this.fromPos = fromPos;
this.uInput = uInput;
result = new G(g);
//value of G gets edited here.
}
It's quite difficult to understand what's going on in the code, since the snippets are non-compilable and the names rather cryptic, but I'll have a go...
The return statement you have in the for loop below looks highly suspect:
public M genM(GameState g, boardPoint p){
M m; // a move
for(/*condition*/){
m = new M(/*parameters*/);
return m;
}
return null;
}
If it's really an unconditional return out of a for loop, then the loop will run for at most one iteration.
This could be a red herring, but again, it's hard to be sure based on the code you've shown us.
You have removed some related code and names types does not really match but i think you have some problem with the object you call as either P or G.
Possibly:
You are cloning G object once and then, in the for loop, operating on the same G object thus affecting all values inside the list.
Basicly, you are changing some values of G and adding it to list several times. At the end all object are same as you are working on same G object.

Categories