Finding a single path in a graph using dfs - java

I am currently trying to find a single path in a graph leading from source to sink. I am trying to implement a method using dfs to achieve this. However, i can't seem to figure out how to make the method to stop the recursion. For example, i have this graph (in matrix form)
0 1 1 0
0 0 0 1
0 0 0 1
0 0 0 0
So i have an edge from node 0 (the source) to node 1 and 2 respectively, and then an edge from 1 and 2 leading to 3 (the sink). The path i would want to have would be 0>1>3, instead i'm getting 0>1>3>2>3. How can i make the recursion stop as soon as a path to the sink is found?
Here is the code for the method:
public void dfsPath(int i) {
boolean[] visited = new boolean[this.edgeCapacities.length];
visited[i] = true;
this.path.add(i); //Integer ArrayList containing the nodes in the path
//loop through all of the nodes in the matrix to find adjacency
for (int j = 0; j < this.edgeCapacities.length; j++) {
//check if edge exists and node has not been visited
if (this.edgeCapacities[i][j] != 0 && !visited[j]) {
//here is the problem, i want the recursion to stop once the sink is found
//it does not work however.
if(j == this.sink) {
visited[j] = true;
this.path.add(j);
return;
} else {
//recursion
dfsPath(j);
}
}
}
Any help would be greatly appreciated. Thanks in advance.

There seem to be several problems with your DFS algorithm:
by creating a new visited list in each recursive call, it always contains only the current node
you are only adding nodes to this.path, but never removing nodes that did not lead to the goal
you never check whether one of your recursive calls reached the goal, thus adding more nodes to a perfectly good path
To fix this, you should remove the current node from this.path at the end of the method, i.e. in case no path has been found. Also, you can just drop the visited array and just check whether the next node is already in the path. That's not quite as fast, but should suffice for your case and make the code less complex. Also, the method should return true or false depending on whether it found a path.
Try this (not tested, but should work).
public boolean dfsPath(int i) {
this.path.add(i); // add current node to path
if (i == this.sink) {
return true; // if current node is sink, return true
// this.path contains nodes from source to sink
}
for (int j = 0; j < this.edgeCapacities.length; j++) {
if (this.edgeCapacities[i][j] != 0 && ! this.path.contains(j)) {
if (dfsPath(j)) {
return true; // found a path -> search no further
}
}
}
this.path.remove(this.path.size() - 1); // pop last node
return false; // no path found
}
Note that I also moved the sink-check out of the loop. This is purely a matter of taste, but it makes the code a bit simpler, as you don't have to add the sink node separately to the path.

Related

Parse Java code with JavaParser and find the statement type of parent nodes

I have made a small program that uses JavaParser [1] to parse Java code and identify the types of statements that appear in the code. This has been implemented successfully. What I want to do next, and is a bit tricky, is to find the parent node for an if-statement, and check whether the first statement of the parent node is a while-loop. After confirming that the above statement is true, I also want to find if this if-statement is the last child of the parent node.
Following you can find an example of the above description:
void example() {
int x = 1;
int y = 1;
while (y < 3) {
while (x < 4) {
x++;
}
if (y < 5) {
y++;
}
}
x = 0;
}
The main question I have with parsing the above code, is how to obtain that the parent node of if (y < 5 ) is a while-loop (while (y < 3)) and secondly, which might be even trickier, is how to identify that the if-statement of this example is the last statement before we skip back to the parent loop. There is also y++; inside the if but it might be skipped if the condition of the if is not true, so I do not want to consider it as the last child of the parent node. I believe what I should do is to check for the last "neighbour"? What I mean by neighbour is the relationship between the second while and the if of this example, i.e. they are at the same level.
My thoughts so far implemented:
//find if the if-statement has a parent node
if (currIf.getParentNode().isPresent()) {
//find if the parent Node is a While loop
Optional<Node> parent = currIf.getParentNode();
parent.get().getBegin();
}
With the above code I am able to check if the if-statement has a parent node and I can find the location of the first while but I do not know how to confirm that it is a while statement and also implement the second described part.
UPDATE:
I managed to find how to check if the parent is a while-loop and currently trying to find a solution on how to identify that the if-statement is the last statement of its level (or hierarchy if you prefer).
Optional<WhileStmt> ifParent = currIf.findAncestor(WhileStmt.class);
//find if the if-statement has a parent node
if (ifParent.isPresent()) {
//find if the parent Node is a While loop
Optional<Node> sameNode = ifParent.get().findFirst(Node.class, n -> n == currIf);
if (sameNode.isPresent()) {
System.out.println(sameNode);
}
}
Your update could give you the wrong result if I am understanding it correctly. Yes, your solution will work if a WhileStmt is the parent, but it also could give you a WhileStmt a bit further up the tree.
Why can't you do something like the following?
boolean parentIsWhileLoop = ifStmtNode.getParent() instanceof WhileStmt;
For determining if the ifStmt is the last node, you could do
Node ifStmtParent = ifStmt.getParent();
List<Node> ifStmtSibilings = ifStmtParent.getChildNodes();
Node lastNode = ifStmtSiblings.get(ifStmtSiblings.size() - 1);
boolean ifStmtIsLast = lastNode == ifStmt;

Find Shortest Path in a Maze with Recursive Algorithm

I made a little recursive algorithm to find a solution to a maze in the following format
###S###
##___##
##_#_##
#__#_##
#E___##
Where a '#' represents a wall, and '_' represents an open space (free to move through). 'S' represents the start location, 'E' represents the end location.
My algorithm works fine, but I'm wondering how to modify it to work for the shortest path.
/**
* findPath()
*
* #param location - Point to search
* #return true when maze solution is found, false otherwise
*/
private boolean findPath(Point location) {
// We have reached the end point, and solved the maze
if (location.equals(maze.getEndCoords())) {
System.out.println("Found path length: " + pathLength);
maze.setMazeArray(mazeArray);
return true;
}
ArrayList<Point> possibleMoves = new ArrayList<Point>();
// Move Right
possibleMoves.add(new Point(location.x + 1, location.y));
// Down Move
possibleMoves.add(new Point(location.x, location.y - 1));
// Move Left
possibleMoves.add(new Point(location.x - 1, location.y));
// Move Up
possibleMoves.add(new Point(location.x, location.y + 1));
for (Point potentialMove : possibleMoves) {
if (spaceIsFree(potentialMove)) {
// Move to the free space
mazeArray[potentialMove.x][potentialMove.y] = currentPathChar;
// Increment path characters as alphabet
if (currentPathChar == 'z')
currentPathChar = 'a';
else
currentPathChar++;
// Increment path length
pathLength++;
// Find the next path to traverse
if (findPath(potentialMove)) {
return true;
}
// Backtrack, this route doesn't lead to the end
mazeArray[potentialMove.x][potentialMove.y] = Maze.SPACE_CHAR;
if (currentPathChar == 'a')
currentPathChar = 'z';
else
currentPathChar--;
// Decrease path length
pathLength--;
}
}
// Previous space needs to make another move
// We will also return false if the maze cannot be solved.
return false;
}
In the first block is where I find the path and break it out. The char[][] array with the path written on it is set as well, which is later printed out as the result.
It works well, but I'm wondering what would be the best way to modify it to not break out after it finds the first successful path, but keep going until it finds the shortest possible path.
I tried doing something like this, modifying the findPath() method and adding a shortestPath and hasFoundPath variable. The first indicating length of the shortest path found so far, and the hasFoundPath variable indicating whether or not we have found any path.
// We have reached the end point, and solved the maze
if (location.equals(maze.getEndCoords())) {
System.out.println("Found path length: " + pathLength);
// Is this path shorter than the previous?
if (hasFoundPath && pathLength < shortestPathLength) {
maze.setMazeArray(mazeArray);
shortestPathLength = pathLength;
} else if (!hasFoundPath) {
hasFoundPath = true;
maze.setMazeArray(mazeArray);
shortestPathLength = pathLength;
}
//return true;
}
But I haven't been able to get it to set the mazeArray to the correct values of any shortest path it may find.
Any guidance would be appreciated :) Thanks
spaceIsFree() method simply makes sure the up/left/down/right coordinates are valid before moving to them. So it makes sure the char is an '_' or 'E' and it isn't out of bounds.
Your code appears to perform a depth-first search (DFS). To find the shortest path you will want to switch to a breadth-first search (BFS). It's not something you can do by adding a few variables to your existing code. It will require rewriting your algorithm.
One way to convert a DFS into a BFS is to get rid of the recursion and switch to using an explicit stack to keep track of which nodes you've visited so far. Each iteration of your search loop, you (1) pop a node off the stack; (2) check if that node is the solution; and (3) push each of its children onto the stack. In pseudo code, that looks like:
Depth-first search
stack.push(startNode)
while not stack.isEmpty:
node = stack.pop()
if node is solution:
return
else:
stack.pushAll(node.children)
If you then switch the stack to a queue this will implicitly become a BFS, and a BFS will naturally find the shortest path(s).
Breadth-first serarch
queue.add(startNode)
while not queue.isEmpty:
node = queue.remove()
if node is solution:
return
else:
queue.addAll(node.children)
A couple of additional notes:
The above algorithms are suitable for trees: mazes that don't have loops. If your mazes have loops then you'll need to make sure you don't revisit nodes you've already seen. In that case, you'll need to add logic to keep track of all the already visited nodes and avoid adding them onto the stack/queue a second time.
As written, these algorithms will find the target node but they don't remember the path that got them there. Adding that is an exercise for the reader.
Here's the BFS-search solution I came up with.
It marks the starting point as "1", then marks each adjacent one that it can travel to as "2", and each adjacent one to the 2's that can be traveled to as "3" and so on.
Then it starts at the end, and goes backwards using the decrementing "level" values which results in the shortest path.
private LinkedList<Point> findShortestPath(Point startLocation) {
// This double array keeps track of the "level" of each node.
// The level increments, starting at the startLocation to represent the path
int[][] levelArray = new int[mazeArray.length][mazeArray[0].length];
// Assign every free space as 0, every wall as -1
for (int i=0; i < mazeArray.length; i++)
for (int j=0; j< mazeArray[0].length; j++) {
if (mazeArray[i][j] == Maze.SPACE_CHAR || mazeArray[i][j] == Maze.END_CHAR)
levelArray[i][j] = 0;
else
levelArray[i][j] = -1;
}
// Keep track of the traversal in a queue
LinkedList<Point> queue = new LinkedList<Point>();
queue.add(startLocation);
// Mark starting point as 1
levelArray[startLocation.x][startLocation.y] = 1;
// Mark every adjacent open node with a numerical level value
while (!queue.isEmpty()) {
Point point = queue.poll();
// Reached the end
if (point.equals(maze.getEndCoords()))
break;
int level = levelArray[point.x][point.y];
ArrayList<Point> possibleMoves = new ArrayList<Point>();
// Move Up
possibleMoves.add(new Point(point.x, point.y + 1));
// Move Left
possibleMoves.add(new Point(point.x - 1, point.y));
// Down Move
possibleMoves.add(new Point(point.x, point.y - 1));
// Move Right
possibleMoves.add(new Point(point.x + 1, point.y));
for (Point potentialMove: possibleMoves) {
if (spaceIsValid(potentialMove)) {
// Able to move here if it is labeled as 0
if (levelArray[potentialMove.x][potentialMove.y] == 0) {
queue.add(potentialMove);
// Set this adjacent node as level + 1
levelArray[potentialMove.x][potentialMove.y] = level + 1;
}
}
}
}
// Couldn't find solution
if (levelArray[maze.getEndCoords().x][maze.getEndCoords().y] == 0)
return null;
LinkedList<Point> shortestPath = new LinkedList<Point>();
Point pointToAdd = maze.getEndCoords();
while (!pointToAdd.equals(startLocation)) {
shortestPath.push(pointToAdd);
int level = levelArray[pointToAdd.x][pointToAdd.y];
ArrayList<Point> possibleMoves = new ArrayList<Point>();
// Move Right
possibleMoves.add(new Point(pointToAdd.x + 1, pointToAdd.y));
// Down Move
possibleMoves.add(new Point(pointToAdd.x, pointToAdd.y - 1));
// Move Left
possibleMoves.add(new Point(pointToAdd.x - 1, pointToAdd.y));
// Move Up
possibleMoves.add(new Point(pointToAdd.x, pointToAdd.y + 1));
for (Point potentialMove: possibleMoves) {
if (spaceIsValid(potentialMove)) {
// The shortest level will always be level - 1, from this current node.
// Longer paths will have higher levels.
if (levelArray[potentialMove.x][potentialMove.y] == level - 1) {
pointToAdd = potentialMove;
break;
}
}
}
}
return shortestPath;
}
The spaceIsValid() is simply ensuring that the space is not out of bounds.

Restore heap condition throughout the entire heap

I'm trying to answer the following programming question:
In the heap.java program, the insert() method inserts a new node in the heap and ensures the heap condition is preserved. Write a toss() method that places a new node in the heap array without attempting to maintain the heap condition. (Perhaps each new item can simply be placed at the end of the array.) Then write a restoreHeap() method that restores the heap condition throughout the entire heap. Using toss() repeatedly followed by a single restoreHeap() is more efficient than using insert() repeatedly when a large amount of data must be inserted at one time. See the description of heapsort for clues. To test your program, insert a few items, toss in some more, and then restore the heap.
I've written the code for the toss function which successfully inserts the node at the end and doesn't modify the heap condition. I'm having problems with the restoreHeap function though and I can't wrap my head around it. I've included the two functions below.
The full code of heap.java is here (includes toss() and restoreHeap() )
toss() - I based this off the insert function
public boolean toss(int key)
{
if(currentSize==maxSize)
return false;
Node newNode = new Node(key);
heapArray[currentSize] = newNode;
currentSize++;
return true;
} // end toss()
restoreHeap() - I based this off the trickleUp function and I'm getting a StackOverflowError.
public void restoreHeap(int index)
{
int parent = (index-1) / 2;
Node bottom = heapArray[index];
while( index > 0 &&
heapArray[parent].getKey() < bottom.getKey() )
{
heapArray[index] = heapArray[parent]; // move it down
index = parent;
parent = (parent-1) / 2;
} // end while
heapArray[index] = bottom;
while(index != 0)
{
restoreHeap(parent++);
}
} // end restoreHeap()
Any ideas? Help appreciated.
I'll give it a shot. Here is a way to do what you asked with some explanation.
Since you know that half of all nodes in a heap are leafs and a leaf, by itself, is a valid heap, you only have to run through the other half of the nodes to make sure they also are valid. If we do this from the bottom and up, we can maintain a valid heap structure "below" as we go up through the heap. This can easily be accomplished by a for loop:
public void rebuildHeap()
{
int half = heapArray.length / 2;
for(int i = half; i >= 0; i--)
restoreHeap(i);
}
How is restoreHeap implemented then?
It's supposed to check the node at index against its children to see if it needs to relocate the node. Because we make sure that the trees below the index node are heaps, we only have to move the index node to the right position. Hence we move it down in the tree.
First we need to locate the children. Since each row in the three have twice as many nodes as the row before, the children can be located like this:
private void restoreHeap(int index)
{
int leftChild = (index * 2) + 1; //+1 because arrays start at 0
int rightChild = leftChild +1;
...
Now you just have to compare the childrens value against your index nodes value. If a child have a bigger value you need to swap the index node with the child node. If both children have a bigger value, you need to swap with the child with the biggest value of the two (to maintain the heap structure after the swap). When the nodes have been swapped you need to call the method again to see if you need to move the index node further down the tree.
...
int biggest = index;
if(leftChild < currentSize && heapArray[leftChild].getKey() > heapArray[index].getKey())
biggest = leftChild; //LeftChild is bigger
if(rightChild < currentSize && heapArray[rightChild].getKey() > heapArray[biggest].getKey())
biggest = rightChild; //RightChild is bigger than both leftChild and the index node
if(biggest != index) //If a swap is needed
{
//Swap
Node swapper = heapArray[biggest];
heapArray[biggest] = heapArray[index];
heapArray[index] = swapper;
restoreHeap(biggest);
}
}

Java depth-first recursive function

Im writing a recursive function in Java (graph theory) to get all paths in a 4x4 table, beginning at a random starting point. Possible directions are horizontal, vertical & diagonal, but I have a requirement that the same location cannot be visited twice.
The script works fine so far, I get a lot of combinations. The problem is that in the for loop of the function, when there is more than one possible way, then I get wrong results in the second and following loops because the boolean[] tempvisited is not getting back to his old values.
I hope there is someone, that may understand my English and my problem too. Here is my code so far:
// here I define a constant input of values:
String letters = "1548987425461854"
// This matrix shows all possible directions from every startpoint in the matrix:
// from the second value, you may get to the following locations: 1,3,5,6 and 7
private int[][] matrix = {
{1,4,5},
{0,2,4,5,6},
{1,3,5,6,7},
{2,6,7},
{0,1,5,8,9},
{0,1,2,4,6,8,9,10},
{1,2,3,5,7,9,10,11},
{2,3,6,10,11},
{4,5,9,12,13},
{4,5,6,8,10,12,13,14},
{5,6,7,9,11,13,14,15},
{6,7,10,14,15},
{8,9,13},
{8,9,10,12,14},
{9,10,11,13,15},
{10,11,14}
};
// Here begins the recursive function
public List<Combination> depthFirst(int vertex, boolean[] visited, Combination zeichen, List<Combination> combis){
// A temporary list of booleans to mark every value position visited or not
boolean[] tempvisited = new boolean[16];
// combis is the whole list of ways, zeichen is just the actual combination
zeichen.name = zeichen.name + this.letters.charAt(vertex);
combis.add(zeichen.name);
//marks actual value as visited
visited[vertex] = true;
for(int i = 0; i < 16; i++){
tempvisited[i] = visited[i];
}//end for
// going to next possible locations
for (int i = 0; i < this.matrix[vertex].length; i++) {
if (!visited[this.matrix[vertex][i]]) {
combis = depthFirst(this.matrix[vertex][i], tempvisited, zeichen, combis);
}//end if
}//end for
return combis;
}
You have the right idea with tempvisited, making a copy. But you're doing so in the wrong place.
You're setting visited[vertex] = true, which means that the visited you passed in is changing. What you want is for visited to never change. Make a copy of it, and make your changes to that copy.
Also, I notice that you use the same zeichen every time. So if you have a path 3 steps long, your combis list with be 3 copies of the same zeichen. That seems incorrect.
You set visited[vertex] to true before the first for loop; you could reset it to false just before you return. If every call undoes the change it did (directly), then every call will return with visited back to its state when that call was made. No tempvisited needed.
Take a look to this other recursive solution (pseudocode) for the Depth First Search (DFS).
void search(Node root) {
if (root == null) return;
visit(root);
root.visited = true;
foreach (Node n in root.adjacent) {
if (n.visited == false)
search(n);
}
}
Actually you don't need a copy of the visited array. Mark the node as visited right before the reccurrent call of depthFirst and then "unmark" it right after the call. Something like:
for (int i = 0; i < this.matrix[vertex].length; i++) {
if (!visited[this.matrix[vertex][i]]) {
visited[this.matrix[vertex][i]] = true;
combis = depthFirst(this.matrix[vertex][i], tempvisited, zeichen, combis);
visited[this.matrix[vertex][i]] = false;
}//end if
}//end for

How to check if a binary tree is complete in Java

I am having a lot of trouble with this task. Using the Wikipedia definition for a complete binary tree:
A complete binary tree is a binary tree in which every level, except possibly the last, is completely filled, and all nodes are as far left as possible
I need a way of checking for these conditions, but no matter how much I try, I can't seem to come up with anything. If I were to pass a TreeNode tree input into a checkComplete method how could I go about going through the binary tree and checking that it is complete? Can anyone help with pseudocode or an explanation of how this is possible? There was another question here: How to determine whether a binary tree is complete?
This one had an answer with pseudocode in it, but I couldn't understand where all the random variables were coming from or what they were meant to represent or why there were two values in brackets in the last 3 lines. If anyone could help with another representation I'd really appreciate it.
int CT()
{
int lh=0, rh=0, sign=1;
if (!root->left && !root->right)
return 1;
if (!root->left && root->right)
return 0;
lh = CT(root->left);
rh = CT(root->right);
if (lh == 0 || rh == 0)
return 0;
if (lh < 0 && rh < 0)
return 0;
if (lh < 0 || rh < 0)
sign = -1;
if (|lh| == |rh| )
return (|lh|+1)*sign;
elseif (rh == lh-1)
return -(|lh|+1);
else return 0;
}
if CT returns '0' - its not a complete tree.
'-' is used to check mismatch in height is encountered on one subtree only.
Traverse the tree left-to-right. There are several critical points at which you'll want to store or compare information:
When you hit the first leaf node.
When you hit subsequent leaf nodes.
When you hit the first leaf node with a different distance from the root.
Since this is homework, you should probably take it the rest of the way from that hint.

Categories