I mam using an implementation of the Depth First Search Algorithm in order to solve a maze. I do not wish for the shortest path to be found but for the fastest way to find a valid path. This is the method i use to solve mazes. Mazes are 2d int arrays where 0 is an open square, 1 is a wall, 2 is a visited square and 9 is the destination.
public class DepthAlgorithm {
/**
* This method returns true when a path is found. It will also fill up the
* list with the path used. It will start from (xn,yn,.....,x2,y2,x1,y2)
* because it will use recursion.
* #param maze 2d array of maze
* #param x the x of the starting position
* #param y the y of the starting position
* #param path a List of the path
* #return True if a path is found
*/
public static boolean searchPath(int [][] maze, int x, int y, List<Integer> path){
// Check if the destination (9) is reached
if (maze[y][x] == 9) {
path.add(x);
path.add(y);
return true;
}
// When the current position is not visited (0) we shall make it visited (2)
if (maze[y][x] == 0) {
maze[y][x] = 2;
//Here we visit all neighbour squares recursively and if a path is found
// we shall fill the path list with the current position.
int dx = -1; // Start and search from starting
int dy = 0; // position (x-1,y)
if (searchPath(maze, x + dx, y + dy, path)) {
path.add(x);
path.add(y);
return true;
}
dx = 1; // Start and search from starting
dy = 0; // position (x+1,y)
if (searchPath(maze, x + dx, y + dy, path)) {
path.add(x);
path.add(y);
return true;
}
dx = 0; // Start and search from starting
dy = -1; // position (x,y-1)
if (searchPath(maze, x + dx, y + dy, path)) {
path.add(x);
path.add(y);
return true;
}
dx = 0; // Start and search from starting
dy = 1; // position (x,y+1)
if (searchPath(maze, x + dx, y + dy, path)) {
path.add(x);
path.add(y);
return true;
}
}
return false;
}
}
My algorithm works fine for small maze sizes. When i want to solve a 50 * 50 maze it's quite quick. When i move to 500 * 500 a Stack Overflow error shows up. I can understand that it shows up because of the many recursive calls of the function but i do not know how to fix it. Is there another way so I can still use the Depth First Search and store my path but without the Stack Overflow? Or are there any changes that can be done in my code so it can be fixed?
public class MazeRunner {
// Maze is a 2d array and it has to be filled with walls peripherally
// with walls so this algorithm can work. Our starting position in this
// will be (1,1) and our destination will be flagged with a 9 which in
// this occasion is (11,8).
private int[][] maze ;
private final List<Integer> path = new ArrayList<>();
public long startTime,stopTime;
public MazeRunner(int [][] maze){
this.maze = maze;
}
public void runDFSAlgorithm(int startingX,int startingY){
startTime = System.nanoTime();
DepthAlgorithm.searchPath(maze,startingX,startingY,path);
stopTime = System.nanoTime();
printPath();
System.out.println("Time for Depth First Algorithm: "+((double) (stopTime-startTime) / 1_000_000)+" milliseconds");
}
public void printPath(){
ListIterator li = path.listIterator(path.size());
int lengthOfPath = (path.size()/2-1);
int fromX,fromY,bool = 0,toX = 0,toY = 0,i = 2;
while(li.hasPrevious()){
if (bool == 0) {
fromX = (int) li.previous();
fromY = (int) li.previous();
toX = (int) li.previous();
toY = (int) li.previous();
System.out.println("From ("+fromY+", "+fromX+") to ("+toY+", "+toX+")");
bool++;
continue;
}
if (bool == 1){
fromX = toX;
fromY = toY;
toX = (int) li.previous();
toY = (int) li.previous();
System.out.println("From ("+fromY+", "+fromX+") to ("+toY+", "+toX+")");
i++;
}
}
System.out.println("\nLength of path is : "+lengthOfPath);
}
public static void main(String[] args){
int [][] maze = {{1,1,1,1,1,1,1,1,1,1,1,1,1},
{1,0,1,0,1,0,1,0,0,0,0,0,1},
{1,0,1,0,0,0,1,0,1,1,1,0,1},
{1,0,0,0,1,1,1,0,0,0,0,0,1},
{1,0,1,0,0,0,0,0,1,1,1,0,1},
{1,0,1,0,1,1,1,0,1,0,0,0,1},
{1,0,1,0,1,0,0,0,1,1,1,0,1},
{1,0,1,0,1,1,1,0,1,0,1,0,1},
{1,0,0,0,0,0,0,0,0,0,1,9,1},
{1,1,1,1,1,1,1,1,1,1,1,1,1}};
MazeRunner p = new MazeRunner(maze);
p.runDFSAlgorithm(startingPoint[0],startingPoint[1]);
}
}
And this is the class i use for my testings. It for sure works for this example but for greater arrays it doesn't. Any suggestions would be appreciated. When i run my program on big arrays i get this following error:
Generally speaking there are only two possibilities that could cause a stackoverflow exception
1.memory of stack is not enough
2.there exist a dead loop which in using recursive means it does't exist an end condition.
Since you algo works for small size maze. It’s possible the reason one. As you know the rule of recursive is first in last out, in JVM all the data of unexecuted functions will be stored in stack which owns a much smaller memory than heap.
You should never use a recursive algorithm for real work unless you know for certain that the depth of the stack will be limited to a reasonable number. Usually that means O(log N), or O(log^2 N) at most.
DFS for a 500x500 maze could put around 250000 function calls on the stack, which is way too many.
You can use DFS if you really want to, but you should maintain your own stack in a separate data structure. BFS would be better though, unless there's some reason you really don't want the shortest path.
In the constructor, how would I represent the top and bottom Diagram parameters with a char[][]?
Casting doesn't work.
public CombineLeftRight(Diagram left, Diagram right, int animationType)
A Constructor that initializes the animationType with the provided parameter value and initializes the board with the diagram resulting from calling TwoDimArrayUtil.appendLeftRight() on the boards associated with the left and right diagrams.
public static char[][] appendLeftRight(char[][] left, char[][] right) {
int numRows = (left.length > right.length) ? left.length : right.length;
int numCols = left[0].length + right[0].length;
char[][] retArray = new char[numRows][numCols];
TwoDimArrayUtil.copyArray(retArray, left, 0, 0);
TwoDimArrayUtil.copyArray(retArray, right, 0, left[0].length);
return retArray;
}
Thank you in advance!
public interface Diagram {
/**
* Returns a two-dimensional array of characters representing a diagram.
*
* #return
*/
public char[][] getBoard();
/**
* Returns the next two-dimensional array of characters to display during an
* animation.
*
* #return
*/
public char[][] nextAnimationStep();
/**
* Number of rows associated with the diagram.
*
* #return
*/
public int getNumberRows();
/**
* Number of columns associated with the diagram.
*
* #return
*/
public int getNumberCols();
}
I am guessing that if your constructor is of this format:
// Constructor
public CombineLeftRight(Diagram left, Diagram right, int animationType){
...
}
Then you need to convert each Diagram into a 2D array of char - something along the lines of
char[][] left2dArr = left.getBoard();
char[][] right2dArr = right.getBoard();
So that you can invoke the static method as you mentioned... like
TwoDimArrayUtil.appendLeftRight(left2dArr, right2dArr);
// or simply
TwoDimArrayUtil.appendLeftRight(left.getBoard(), right.getBoard());
putting it all together (still guessing here as there is not enough code in your question to know for sure), your constructor could look like:
// Constructor
public CombineLeftRight(Diagram left, Diagram right, int animationType){
...
TwoDimArrayUtil.appendLeftRight(left.getBoard(), right.getBoard());
...
}
I am trying to figure out the proper way to call arrays from the area method, which are then supposed to calculate the area of the points given. Not sure what the proper way to select the specific x and y coordinates from each array is.
MyPolygon class
import java.util.ArrayList;
import java.awt.geom.Point2D;
import java.awt.geom.Point2D.Double;
/**
* A class that represents a geometric polygon. Methods are provided for adding
* a point to the polygon and for calculating the perimeter and area of the
* polygon.
*/
class MyPolygon {
// list of the points of the polygon
private ArrayList<Point2D.Double> points;
/**
* Constructs a polygon with no points in it.
*/
public MyPolygon() {
points = new ArrayList<Point2D.Double>();
}
/**
* Adds a point to the end of the list of points in the polygon.
*
* #param x
* The x coordinate of the point.
* #param y
* The y coordinate of the point.
*/
public void add(double x, double y) {
points.add(new Point2D.Double(x, y));
}
/**
* Calculates and returns the perimeter of the polygon.
*
* #return 0.0 if < 2 points in polygon, otherwise returns the sum of the
* lengths of the line segments.
*/
public double perimeter() {
if (points.size() < 2) {
return 0.0;
}
int i = 0;
double d = 0;
double total = points.get(0).distance(points.get(points.size() - 1));
while (i < points.size() - 1) {
Point2D.Double point1 = points.get(i);
// double x = point1.x;
// double y = point1.y;
Point2D.Double point2 = points.get(i + 1);
// double x1 = point2.x;
// double y1 = point2.y;
d = point1.distance(point2);
// d = Math.sqrt(Math.pow(x1 - x,2) + Math.pow(y1 - y, 2));
total = total + d;
i++;
}
return total;
}
/**
* Calculates and returns the area of the polygon.
*
* #return 0.0 if < 3 points in the polygon, otherwise returns the area of
* the polygon.
*/
public double area() {
int i = 0;
double a = 0;
double total = 0;
total = total + a;
if (points.size() < 3) {
return 0.0;
}
for (int m = 0; m < points.size(); m++) {
total = total + (points[m].x() * points[m + 1].y()) - (points[m].y() * points[m + 1].x());
}
return 0.5 * total;
}
}
Tester Class
class PolygonTester {
public static void main(String args[]) {
MyPolygon poly = new MyPolygon();
poly.add(1.0,1.0);
poly.add(3.0,1.0);
poly.add(1.0,3.0);
System.out.println(poly.perimeter());
System.out.println(poly.area());
}
}
Your headline is actually already the solution. You use points[m] which is array notation. But points ist not an array. It is a list. Use points.get(int i) instead, as you did in perimeter().
You're going to run out of bounds on the list. Your for loop continues while m < size(). However you access m+1 in your calculation. So if the list contains 5 elements and m = 4, (4 < 5) so keep looping, you will then access m + 1 which is 5. You don't have an index of 5 since these lists are 0 based.
Also the code is probably not compiling because you're using array syntax to access a list. You should say points.get(m)
The solution is quite simple, and is given away by your title (which I assume to be a compiler error.)
You are treating points as an array, which it is not. You access elements of an ArrayList slightly differently: you use points.get(m) instead of points[m]. If you make that change in area, it will work.
ArrayLists are not arrays. They are objects that are indexed with the get(int) method.
Wherever you have points[m], or something similar, replace it with points.get(m). The line would then become:
total = total + (points.get(m).x() * points.get(m + 1).y()) - (points.get(m).y() * points.get(m + 1).x());
That should clear up that issue, but you will still probably get an IndexOutOfBoundsException on the last iteration of the loop, because you will be trying to index m + 1 when m is the last index. You should change your code depending on how you want it to handle the last element.
I am modifying a graph implementation to compute the all pairs shortest path matrix using Floyd's algorithm. The graph has both adjacency linked list and matrix implementations. For now I am using adjacency matrix because it its needed for this algorithm.
abstract public class GraphMatrix<V,E> extends AbstractStructure<V> implements Graph<V,E>{
/**
* Number of vertices in graph.
*/
protected int size; // allocation size for graph
/**
* The edge data. Every edge appears on one (directed)
* or two (undirected) locations within graph.
*/
protected Object data[][]; // matrix - array of arrays
/**
* Translation between vertex labels and vertex structures.
*/
protected Map<V,GraphMatrixVertex<V>> dict; // labels -> vertices
/**
* List of free vertex indices within graph.
*/
protected List<Integer> freeList; // available indices in matrix
/**
* Whether or not graph is directed.
*/
protected boolean directed; // graph is directed
/**
* Constructor of directed/undirected GraphMatrix. Protected constructor.
*
* #param size Maximum size of graph.
* #param dir True if graph is to be directed.
*/
protected GraphMatrix(int size, boolean dir)
{
this.size = size; // set maximum size
directed = dir; // fix direction of edges
// the following constructs a size x size matrix
data = new Object[size][size];
// label to index translation table
dict = new Hashtable<V,GraphMatrixVertex<V>>(size);
// put all indices in the free list
freeList = new SinglyLinkedList<Integer>();
for (int row = size-1; row >= 0; row--)
freeList.add(new Integer(row));
}
.
.
.
public Object[][] AllPairsShortestPath()
{
//First, data array needs to be copied to a new array so that it is not corrupted.
Object[][] weight_matrix = data.clone();
for(int k = 0; k < size; k++)
{
for(int i = 0; i < size; i++)
{
for(int j = 0; j < size; j++)
{
if((weight_matrix + weight_matrix[k][j])<weight_matrix[i][j])
{
//New shorter path is found
}
}
}
}
return weight_matrix;
}
My question is how can I reference the weight_matrix elements so that they can be compared?
Here is the edge class that is in the Object matrix:
public class Edge<V,E>
{
/**
* Two element array of vertex labels.
* When necessary, first element is source.
*/
protected V here, there; // labels of adjacent vertices
/**
* Label associated with edge. May be null.
*/
protected E label; // edge label
/**
* Whether or not this edge has been visited.
*/
protected boolean visited; // this edge visited
/**
* Whether or not this edge is directed.
*/
protected boolean directed; // this edge directed
/**
* Construct a (possibly directed) edge between two labeled
* vertices. When edge is directed, vtx1 specifies source.
* When undirected, order of vertices is unimportant. Label
* on edge is any type, and may be null.
* Edge is initially unvisited.
*
* #post edge associates vtx1 and vtx2; labeled with label
* directed if "directed" set true
*
* #param vtx1 The label of a vertex (source if directed).
* #param vtx2 The label of another vertex (destination if directed).
* #param label The label associated with the edge.
* #param directed True iff this edge is directed.
*/
public Edge(V vtx1, V vtx2, E label,
boolean directed)
{
here = vtx1;
there = vtx2;
this.label = label;
visited = false;
this.directed = directed;
}
/**
* Returns the first vertex (or source if directed).
*
* #post returns first node in edge
*
* #return A vertex; if directed, the source.
*/
public V here()
{
return here;
}
/**
* Returns the second vertex (or source if undirected).
*
* #post returns second node in edge
*
* #return A vertex; if directed, the destination.
*/
public V there()
{
return there;
}
/**
* Sets the label associated with the edge. May be null.
*
* #post sets label of this edge to label
*
* #param label Any object to label edge, or null.
*/
public void setLabel(E label)
{
this.label = label;
}
/**
* Get label associated with edge.
*
* #post returns label associated with this edge
*
* #return The label found on the edge.
*/
public E label()
{
return label;
}
/**
* Test and set visited flag on vertex.
*
* #post visits edge, returns whether previously visited
*
* #return True iff edge was visited previously.
*/
public boolean visit()
{
boolean was = visited;
visited = true;
return was;
}
/**
* Check to see if edge has been visited.
*
* #post returns true iff edge has been visited
*
* #return True iff the edge has been visited.
*/
public boolean isVisited()
{
return visited;
}
/**
* Check to see if edge is directed.
*
* #post returns true iff edge is directed
*
* #return True iff the edge has been visited.
*/
public boolean isDirected()
{
return directed;
}
/**
* Clear the visited flag associated with edge.
*
* #post resets edge's visited flag to initial state
*/
public void reset()
{
visited = false;
}
/**
* Returns hashcode associated with edge.
*
* #post returns suitable hashcode
*
* #return An integer code suitable for hashing.
*/
public int hashCode()
{
if (directed) return here().hashCode()-there().hashCode();
else return here().hashCode()^there().hashCode();
}
/**
* Test for equality of edges. Undirected edges are equal if
* they connect the same vertices. Directed edges must have same
* direction.
*
* #post returns true iff edges connect same vertices
*
* #param o The other edge.
* #return True iff this edge is equal to other edge.
*/
public boolean equals(Object o)
{
Edge<?,?> e = (Edge<?,?>)o;
return ((here().equals(e.here()) &&
there().equals(e.there())) ||
(!directed &&
(here().equals(e.there()) &&
there().equals(e.here()))));
}
/**
* Construct a string representation of edge.
*
* #post returns string representation of edge
*
* #return String representing edge.
*/
public String toString()
{
StringBuffer s = new StringBuffer();
s.append("<Edge:");
if (visited) s.append(" visited");
s.append(" "+here());
if (directed) s.append(" ->");
else s.append(" <->");
s.append(" "+there()+">");
return s.toString();
}
}
I guess
((weight_matrix + weight_matrix[k][j])<weight_matrix[i][j])
is not what you want. IIRC, Floyd's as follows:
((weight_matrix[i][k] + weight_matrix[k][j])<weight_matrix[i][j])
IF YOUR weight_matrix were a matrix of weights (take a look here for more floyd). Size, in this implementation, would be the number of vertices you got on the graph.
If each edge had a weight, you could do
(( ((Edge)weight_matrix[i][k]).getValue() + ((Edge)weight_matrix[k][j]).getValue()) < ((Edge)weight_matrix[i][j]).getValue())
If all edge weights are equal, you could tell getValue() to return 1 always, and voilá.