Recursion and StackOverflow - what should I use instead? - java

I have a piece of code:
private void colorize(int color, int x, int y) {
visited[x][y] = true;
if (x + 1 < d)
if (board[x + 1][y] == board[x][y] && visited[x + 1][y] == false)
colorize(color, x + 1, y);
if (x - 1 >= 0)
if (board[x - 1][y] == board[x][y] && visited[x - 1][y] == false)
colorize(color, x - 1, y);
if (y + 1 < d)
if (board[x][y + 1] == board[x][y] && visited[x][y + 1] == false)
colorize(color, x, y + 1);
if (y - 1 >= 0)
if (board[x][y - 1] == board[x][y] && visited[x][y - 1] == false)
colorize(color, x, y - 1);
board[x][y] = color;
}
I call it: colorize(int random, int 0, int 0). This gives me stackoverflow even for a small table (20x20). How can I do this without recursion?

The code as given seems fine.
There is a question as to what d is, but I'm assuming that it is correctly the width of a square grid.
It's possible that you have a problem in whatever code calls this, but the code you have given us should not have a stack overflow.
Building off of Måns Rolandi Danielsson's answer, here is one that doesn't use the explicit stack, but builds one on the heap. My java is extremely rusty, but this should work. If anyone has fixes for this code, feel free to fix it.
Instead of getting a stack overflow, at large table sizes I get a java.lang.OutOfMemoryError: Java heap space error instead. You could probably use a set or some other data structure (rather than a linked list) to optimize memory usage.
import java.util.Queue;
import java.util.LinkedList;
class Pair<L,R> {
private L l;
private R r;
public Pair(L l, R r){
this.l = l;
this.r = r;
}
public L getL(){ return l; }
public R getR(){ return r; }
}
public class HelloW {
static int d = 20;
static boolean[][] visited = new boolean[d][d];
static int[][] board = new int[d][d];
static Queue<Pair<Integer, Integer>> Q = new LinkedList<Pair<Integer, Integer>>();
static void colorize(int color, int orig_x, int orig_y) {
Q.add(new Pair<Integer, Integer>(orig_x, orig_y));
while (Q.isEmpty() == false) {
Pair<Integer,Integer> foo = Q.remove();
int x = foo.getL();
int y = foo.getR();
int old_color = board[x][y];
visited[x][y] = true;
board[x][y] = color;
if (x + 1 < d)
if (board[x + 1][y] == old_color && visited[x + 1][y] == false)
Q.add(new Pair<Integer, Integer>(x+1, y));
if (x - 1 >= 0)
if (board[x - 1][y] == old_color && visited[x - 1][y] == false)
Q.add(new Pair<Integer, Integer>(x-1, y));
if (y + 1 < d)
if (board[x][y + 1] == old_color && visited[x][y + 1] == false)
Q.add(new Pair<Integer, Integer>(x, y+1));
if (y - 1 >= 0)
if (board[x][y - 1] == old_color && visited[x][y - 1] == false)
Q.add(new Pair<Integer, Integer>(x, y-1));
}
}
public static void main (String[] args) {
colorize(1, 0, 0);
}
}

I just copied your code and ran it like you can see below, and it works perfect, ends up with a matrix full of "true"'s and a matrix full of ones:
static int d = 20;
static boolean[][] visited = new boolean[d][d];
static int[][] board = new int[d][d];
static void colorize(int color, int x, int y) {
visited[x][y] = true;
if (x + 1 < d)
if (board[x + 1][y] == board[x][y] && visited[x + 1][y] == false)
colorize(color, x + 1, y);
if (x - 1 >= 0)
if (board[x - 1][y] == board[x][y] && visited[x - 1][y] == false)
colorize(color, x - 1, y);
if (y + 1 < d)
if (board[x][y + 1] == board[x][y] && visited[x][y + 1] == false)
colorize(color, x, y + 1);
if (y - 1 >= 0)
if (board[x][y - 1] == board[x][y] && visited[x][y - 1] == false)
colorize(color, x, y - 1);
board[x][y] = color;
}
public static void main(String[] args)
{
colorize(1, 0, 0);
}
EDIT: the test program runs fine for d = 20 on my computer, however if I increase to d = 100 I get the StackOverflow. It seems the algorithm is more or less fine, but the recursion goes unnecessary deep, there ought to be a more elegant formulation.

Your code works correctly as far as I can tell; the only thing that could affect it is if another thread came and modified one of your data structures during the recursion, or if you have over-simplified it before posting.

Related

How to avoid StackOverflow Error in Recursive MazeSolver

Like many other java students in college, I need to develop a maze program that solves the maze. My solveMaze method that implements recursion returned a stackoverflow runtime error. How do I solve this problem please? Does this have to do with my algorithm? Thanks in advance.
A) I created a solution maze that array that's going to hold the path to the exit.
B) Then, I implemented a method solveMaze() that took a step toward the exit everytime it's called.
Note: The isWall() method checks if the position you're moving to is a wall or not.
public void showPath() {
int[][] sol = new int[m.length][m[0].length];
for (int j = 0; j < sol.length; j++) {
for (int i = 0; i < sol[0].length; i++) {
sol[j][i] = m[j][i];
}
}
if (solveMaze(sol, m.length - 1, 0, exitCords) == false)
System.out.println("Solution doesn't exist");
else {
for (int y = 0; y < sol.length; y++) {
for (int x = 0; x < sol[0].length; x++) {
if (sol[y][x] == exitCords[0] && sol[y][x] == exitCords[1]) {
System.out.print("E ");
} else {
if (sol[y][x] == 1) {
System.out.print(" ");
} else if (sol[y][x] == 3) {
System.out.print("~");
} else {
System.out.print("# ");
}
}
}
System.out.println();
}
}
}
public boolean solveMaze(int[][] sol, int y, int x, int[] exitCords) {
//exitCords[] is a one-dimensional array that holds the x and y coordinate of the exit point on a maze.
if (y == exitCords[1] && x == exitCords[0]) {//Base Case
return true;
}
//North
if (!isWall(x, y - 1) && sol[y - 1][x] != 3) {
sol[y][x] = 3;//3 is assigned to positions you already visited.
y--;
sol[y][x] = 3;
//Implement recursion to call the solveMaze again on this line.
solveMaze(sol, y, x, exitCords);
return true;
}
//South
else if (!isWall(x, y + 1) && sol[y + 1][x] != 3) {
sol[y][x] = 3;
y++;
sol[y][x] = 3;
solveMaze(sol, y, x, exitCords);
return true;
}
//East
else if (!isWall(x + 1, y) && sol[y][x + 1] != 3) {
sol[y][x] = 3;
x++;
sol[y][x] = 3;
solveMaze(sol, y, x, exitCords);
return true;
}
//West
else if (!isWall(x - 1, y) && sol[y][x - 1] != 3) {
sol[y][x] = 3;
x--;
sol[y][x] = 3;
solveMaze(sol, y, x, exitCords);
return true;
}
/*The following line of code are to get out of dead ends and replace every position near a dead end with a wall*/
else if ((isWall(x, y - 1) && isWall(x, y + 1) && isWall(x + 1, y)) || (isWall(x, y - 1) && isWall(x, y + 1) && isWall(x - 1, y))
|| (isWall(x - 1, y) && isWall(x, y + 1) && isWall(x + 1, y)) || (isWall(x - 1, y) && isWall(x, y - 1) && isWall(x + 1, y))) {
if (isWall(x, y - 1) && isWall(x, y + 1) && isWall(x + 1, y)) {
sol[y][x] = 0;
solveMaze(sol, y, x - 1, exitCords);
return true;
}
if (isWall(x, y - 1) && isWall(x, y + 1) && isWall(x - 1, y)) {
sol[y][x] = 0;
solveMaze(sol, y, x + 1, exitCords);
return true;
}
if (isWall(x - 1, y) && isWall(x, y + 1) && isWall(x + 1, y)) {
sol[y][x] = 0;
solveMaze(sol, y - 1, x, exitCords);
return true;
}
if (isWall(x - 1, y) && isWall(x, y - 1) && isWall(x + 1, y)) {
sol[y][x] = 0;
solveMaze(sol, y + 1, x, exitCords);
return true;
}
}
return false;
}
You have different ways to solve the problem:
The first one is to rewrite your code without using recursion (no luck for tail recursion - Java doesn't have optimization for it)
Another way is to increase stack size using -Xss option
Or you can add actual depth check to solveMaze method, e.g.:
public void showPath() {
// ...
if (solveMaze(sol, m.length - 1, 0, exitCords , 0) == false) {
// ...
}
public boolean solveMaze(int[][] sol, int y, int x, int[] exitCords, int depth) {
if (depth > 64) {
return false;
}
// ...
solveMaze(sol, y, x, exitCords, depth + 1);
// ...
}
A stack overflow error means that your recursion has gone deeper than the language allows. For a small maze, this shouldn't happen, unless you are revisiting locations in the maze. As your code does not seem to make any effort to avoid that, you might want to fix that.

Boolean method to determine consecutive numbers

Write a method named consecutive that accepts three integers as parameters and returns true if they are three consecutive numbers; that is, if the numbers can be arranged into an order such that there is some integer k such that the parameters' values are k, k+1, and k+2. Your method should return false if the integers are not consecutive. Note that order is not significant; your method should return the same result for the same three integers passed in any order.
For example, the calls consecutive(1, 2, 3), consecutive(3, 2, 4), and consecutive(-10, -8, -9) would return true. The calls consecutive(3, 5, 7), consecutive(1, 2, 2), and consecutive(7, 7, 9) would return false.
This is what I have so far and keep getting infinite loop error and skipped tests
public boolean consecutive(int x, int y, int z) {
Scanner kb = new Scanner(System.in);
x = kb.nextInt();
y = kb.nextInt();
z = kb.nextInt();
if (((x < y && x < z) && (y < z && ((y - x) == 1) && ((z - x) == 2))) 
||((z < y && ((z - x) == 1) && ((y - x) == 2)))) 
{
return true;
} else if (((y < x && y < z)&& (x < z && ((x - y) == 1) && ((z - y) == 2))) 
|| ((z < x && ((z - y) == 1) && ((x - y) == 2))))
{
return true;
} else if (((z < x && z < y)&& (y < x && ((y - z) == 1) && ((x - z) == 2))) 
||((x < y && ((x - z) == 1) && ((y - z) == 2))))
{
return true;
} else {
return false;
}
What you have there is serious overkill and pretty much unreadable to anyone who hasn't spent a large proportion of their career in C :-)
You should always strive for readability (and hence maintainability) first, reverting to less readable code only when absolutely necessary. Even if you do revert, you should then document why and what you've done so the next poor soul that has to maintain your code won't be cursing your name.
For this specific case, what you are attempting can be achieved in much simpler code such as the following (pseudo-code):
def areConsecutive(a, b, c):
if a > b: swap a, b
if b > c: swap b, c
if a > b: swap a, b
return (b - a == 1) and (c - b == 1)
The three if statements are simply an unrolled bubble sort to ensure a, b and c are in ascending order, then you simply check to ensure the difference between them is one in both cases.
There's no need to put them into a list or array to sort them since sorting three items is relatively easy (the swap can be done with int t = a; a = b; b = t;).
In terms of Java code (once you've moved the input to outside the function where it belongs), you'd end up with something like:
bool areConsecutive(int a, int b, int c) {
int t;
if (a > b) { t = a; a = b; b = t; }
if (b > c) { t = b; b = c; c = t; }
if (a > b) { t = a; a = b; b = t; }
return (b - a = 1) && (c - b == 1);
}
When you are passing value why using scanner?
Remove those lines and its working. You can use another logic to determine consecutive numbers.
public boolean consecutive(int x, int y, int z) {
if (((x < y && x < z) && (y < z && ((y - x) == 1) && ((z - x) == 2))) ||((z < y && ((z - x) == 1) && ((y - x) == 2)))) {
return true;
} else if (((y < x && y < z)&& (x < z && ((x - y) == 1) && ((z - y) == 2))) ||
((z < x && ((z - y) == 1) && ((x - y) == 2)))){
return true;
} else if (((z < x && z < y)&& (y < x && ((y - z) == 1) && ((x - z) == 2))) ||((x < y && ((x - z) == 1) && ((y - z) == 2)))){
return true;
} else
return false;
}
Just Remove these code:
Scanner kb = new Scanner(System.in);
x = kb.nextInt();
y = kb.nextInt();
z = kb.nextInt();
Or use Like this:
public class test{
public static void main(String[] args) {
Scanner kb = new Scanner(System.in);
x = kb.nextInt();
y = kb.nextInt();
z = kb.nextInt();
System.out.println("Result:" + consecutive(x, y, z));
}
public static boolean consecutive(int x, int y, int z) {
if (((x < y && x < z) && (y < z && ((y - x) == 1) && ((z - x) == 2))) || ((z < y && ((z - x) == 1) && ((y - x) == 2)))) {
return true;
} else if (((y < x && y < z) && (x < z && ((x - y) == 1) && ((z - y) == 2)))
|| ((z < x && ((z - y) == 1) && ((x - y) == 2)))) {
return true;
} else if (((z < x && z < y) && (y < x && ((y - z) == 1) && ((x - z) == 2))) || ((x < y && ((x - z) == 1) && ((y - z) == 2)))) {
return true;
} else {
return false;
}
}
}
Create a list with the numbers, sort it and do de diference between the elements:
public static boolean myConsecutive(int x, int y, int z) {
final List<Integer> list = new ArrayList<>();
list.add(x);
list.add(y);
list.add(z);
Collections.sort(list);
return (list.get(2) - list.get(1) == 1 && list.get(1) - list.get(0) == 1);
}
The consecutive method is passed with three values , then why you are reading from the console.
create an array with the size of 3 elements.
Sort the arrays using Arrays.Sort method
Check the difference between the second and the first number is 1 and difference between Third and the second number is 1.
Code :
public boolean consecutive(int x, int y, int z) {
int [] numbers = new int [3];
numbers[0] = x;
numbers[1] = y;
numbers[2] = z;
Arrays.sort(numbers);
boolean isConsecutive = (numbers[1]==numbers[0]+1)&&(numbers[2]==numbers[1]+1);
return isConsecutive;
}

StackOverFlowError when recursing

I'm programming a game using a recursive algorithm but I got "StackOverFlow error" when compiling it. I'm aware that that's probably due to not having a good end clause and it's re-cursing forever. I'm just trying to get some help on how to fix it.
I'm also aware that the code I'll be posting is a bit too much but I want to provide as much info as I can. Any doubts, just ask.
It starts with the following call:
Integer matrix[][] = new Integer[5][5];
Deque<String> path = new ArrayDeque<>();
ArrayList<Deque<String>> paths = new ArrayList<>();
CoordenateList cList = new CoordenateList();
solver2(matrix, 0, 0, 1, path, paths, cList);
The "solver2" method and the auxiliar methods are the following:
public static void solver2(Integer[][] matrix, int x, int y, int num,
Deque<String> path, ArrayList<Deque<String>> paths, CoordenateList cList) {
if (cList.getCoordenateByKey(Integer.toString(y) + "," + Integer.toString(x)) == null) {
Coordenate c = new Coordenate((Integer.toString(y) + "," + Integer.toString(x))); //substitir nos IF's
cList.addCoordenate(c);
}
if (y - 3 < 0 || (cList.getCoordenateByKey(Integer.toString(y) + "," + Integer.toString(x)).getVisited())[0] == true || matrix[y - 3][x] != null) {
//NORTE
if (x + 3 > matrix.length - 1 || (cList.getCoordenateByKey(Integer.toString(y) + "," + Integer.toString(x)).getVisited())[1] == true || matrix[y][x + 3] != null) {
//ESTE
if (y + 3 > matrix.length - 1 || (cList.getCoordenateByKey(Integer.toString(y) + "," + Integer.toString(x)).getVisited())[2] == true || matrix[y + 3][x] != null) {
//SUL
if (x - 3 < 0 || (cList.getCoordenateByKey(Integer.toString(y) + "," + Integer.toString(x)).getVisited())[3] == true || matrix[y][x - 3] != null) {
//OESTE
if (y - 2 < 0 || x + 2 > matrix.length - 1 || (cList.getCoordenateByKey(Integer.toString(y) + "," + Integer.toString(x)).getVisited())[4] == true || matrix[y - 2][x + 2] != null) {
//NE
if (y + 2 > matrix.length - 1 || x + 2 > matrix.length - 1 || (cList.getCoordenateByKey(Integer.toString(y) + "," + Integer.toString(x)).getVisited())[5] == true || matrix[y + 2][x + 2] != null) {
//SE
if (y + 2 > matrix.length - 1 || x - 2 < 0 || (cList.getCoordenateByKey(Integer.toString(y) + "," + Integer.toString(x)).getVisited())[6] == true || matrix[y + 2][x - 2] != null) {
//SO
if (y - 2 < 0 || x - 2 < 0 || (cList.getCoordenateByKey(Integer.toString(y) + "," + Integer.toString(x)).getVisited())[7] == true || matrix[y - 2][x - 2] != null) {
//NO
if (num == matrix.length * matrix.length) {
Deque<String> aux = new ArrayDeque<>();
aux.addAll(path);
paths.add(aux);
path.pop();
cleanRecord(num, matrix, cList); //desnecessário
num--;
} else {
//LOSER
path.pop();
num--;
y = getCoordenatePrevious(num, matrix)[1];
x = getCoordenatePrevious(num, matrix)[0];
num++;
cleanRecord(num, matrix, cList);
num--;
}
} else {
matrix[y - 2][x - 2] = num + 1;
(cList.getCoordenateByKey(Integer.toString(y) + "," + Integer.toString(x)).getVisited())[7] = true;
path.push(Integer.toString(y + 2) + "," + Integer.toString(x - 2));
solver2(matrix, x - 2, y + 2, num + 1, path, paths, cList);
}
} else {
matrix[y + 2][x - 2] = num + 1;
(cList.getCoordenateByKey(Integer.toString(y) + "," + Integer.toString(x)).getVisited())[6] = true;
path.push(Integer.toString(y + 2) + "," + Integer.toString(x - 2));
solver2(matrix, x - 2, y + 2, num + 1, path, paths, cList);
}
} else {
matrix[y + 2][x + 2] = num + 1;
(cList.getCoordenateByKey(Integer.toString(y) + "," + Integer.toString(x)).getVisited())[5] = true;
path.push(Integer.toString(y + 2) + "," + Integer.toString(x + 2));
solver2(matrix, x + 2, y + 2, num + 1, path, paths, cList);
}
} else {
matrix[y - 2][x + 2] = num + 1;
(cList.getCoordenateByKey(Integer.toString(y) + "," + Integer.toString(x)).getVisited())[4] = true;
path.push(Integer.toString(y - 2) + "," + Integer.toString(x + 2));
solver2(matrix, x + 2, y - 2, num + 1, path, paths, cList);
}
} else {
matrix[y][x - 3] = num + 1;
(cList.getCoordenateByKey(Integer.toString(y) + "," + Integer.toString(x)).getVisited())[3] = true;
path.push(Integer.toString(y) + "," + Integer.toString(x - 3));
solver2(matrix, x - 3, y, num + 1, path, paths, cList);
}
} else {
matrix[y + 3][x] = num + 1;
(cList.getCoordenateByKey(Integer.toString(y) + "," + Integer.toString(x)).getVisited())[2] = true;
path.push(Integer.toString(y + 3) + "," + Integer.toString(x));
solver2(matrix, x, y + 3, num + 1, path, paths, cList);
}
} else {
matrix[y][x + 3] = num + 1;
(cList.getCoordenateByKey(Integer.toString(y) + "," + Integer.toString(x)).getVisited())[1] = true;
path.push(Integer.toString(y) + "," + Integer.toString(x + 3));
solver2(matrix, x + 3, y, num + 1, path, paths, cList);
}
} else {
matrix[y - 3][x] = num + 1;
(cList.getCoordenateByKey(Integer.toString(y) + "," + Integer.toString(x)).getVisited())[0] = true;
path.push(Integer.toString(y - 3) + "," + Integer.toString(x));
solver2(matrix, x, y - 3, num + 1, path, paths, cList);
}
int cont = 0;
if (checkIfNumExists(num, matrix)) {
boolean[] b = cList.getCoordenateByKey(Integer.toString(getCoordenatePrevious(num, matrix)[1]) + "," + Integer.toString(getCoordenatePrevious(num, matrix)[0])).getVisited();
if (y - 3 >= 0 && matrix[y - 3][x] == null && b[0] == false) {
//NORTE
cont++;
solver2(matrix, x, y, num, path, paths, cList);
} else if (x + 3 < matrix.length && matrix[y][x + 3] == null && b[1] == false) {
//ESTE
cont++;
solver2(matrix, x, y, num, path, paths, cList);
} else if (y + 3 < matrix.length && matrix[y + 3][x] == null && b[2] == false) {
//SUL
cont++;
solver2(matrix, x, y, num, path, paths, cList);
} else if (x - 3 >= 0 && matrix[y][x - 3] == null && b[0] == false && b[3] == false) {
//OESTE
cont++;
solver2(matrix, x, y, num, path, paths, cList);
} else if (y - 2 >= 0 && x + 2 < matrix.length && matrix[y - 2][x + 2] == null && b[4] == false) {
//NE
cont++;
solver2(matrix, x, y, num, path, paths, cList);
} else if (y + 2 < matrix.length && x + 2 < matrix.length && matrix[y + 2][x + 2] == null && b[5] == false) {
//SE
cont++;
solver2(matrix, x, y, num, path, paths, cList);
} else if (y + 2 < matrix.length && x - 2 >= 0 && matrix[y + 2][x - 2] == null && b[6] == false) {
//SO
cont++;
solver2(matrix, x, y, num, path, paths, cList);
} else if (y - 2 >= 0 && x - 2 >= 0 && matrix[y - 2][x - 2] == null && b[7] == false) {
//NO
cont++;
solver2(matrix, x, y, num, path, paths, cList);
}
}
if (cont == 0 && checkIfNumExists(num, matrix)) {
if (num != 1) {
num--;
path.pop();
cleanRecord(num + 1, matrix, cList);
cleanMatrixAbove(num, matrix, cList);
}
}
}
/**
* returns the coordenates of the num
*
* #param num
* #param matrix
* #return
*/
public static int[] getCoordenatePrevious(int num, Integer[][] matrix) {
for (int i = 0; i < matrix.length; i++) {
for (int j = 0; j < matrix.length; j++) {
if (matrix[i][j] != null && matrix[i][j] == num) {
int[] array = new int[2];
array[0] = j; //x
array[1] = i; //y
return array;
}
}
}
return null;
}
/**
* cleans the visited record of the num
*
* #param num
* #param matrix
* #param cList
*/
public static void cleanRecord(int num, Integer[][] matrix, CoordenateList cList) {
if (checkIfNumExists(num, matrix)) {
Coordenate c = cList.getCoordenateByKey(Integer.toString(getCoordenatePrevious(num, matrix)[1]) + "," + Integer.toString(getCoordenatePrevious(num, matrix)[0]));
c.cleanVisited();
}
}
/**
* sets null every number in the matrix that are bigger than num
*
* #param num
* #param matrix
* #param cList
*/
public static void cleanMatrixAbove(int num, Integer[][] matrix, CoordenateList cList) {
for (int i = 0; i < matrix.length; i++) {
for (int j = 0; j < matrix.length; j++) {
if (matrix[i][j] != null && matrix[i][j] > num) {
matrix[i][j] = null;
}
}
}
}
/**
* checks if the num exists in the matrix
*
* #param num
* #param matrix
* #return
*/
public static boolean checkIfNumExists(int num, Integer[][] matrix) {
for (int i = 0; i < matrix.length; i++) {
for (int j = 0; j < matrix.length; j++) {
if (matrix[i][j] != null && matrix[i][j] == num) {
return true;
}
}
}
return false;
}
The other classes (Coordenate, CoordenateList) are the following:
public class Coordenate {
String keyID;
boolean[] visited;
public Coordenate(String keyID) {
this.keyID = keyID;
this.visited = new boolean[8];
}
public String getKeyID() {
return this.keyID;
}
public int getXFromKeyID() {
String[] aux = this.keyID.split(",");
int xaux = Integer.parseInt(aux[0]);
return xaux;
}
public int getYFromKeyID() {
String[] aux = this.keyID.split(",");
int yaux = Integer.parseInt(aux[1]);
return yaux;
}
public boolean[] getVisited() {
return visited;
}
public void cleanVisited() {
visited = new boolean[8];
}
public boolean allVisited() {
for (int i = 0; i < 8; i++) {
if (visited[i] = false) {
return false;
}
}
return true;
}
#Override
public String toString() {
return "Coordenate{" + "keyID=" + keyID + ", visited=" + visited + '}';
}
#Override
public int hashCode() {
int hash = 3;
return hash;
}
#Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final Coordenate other = (Coordenate) obj;
if (!Objects.equals(this.keyID, other.keyID)) {
return false;
}
return true;
}
}
public class CoordenateList {
public ArrayList<Coordenate> coordenateList;
public CoordenateList() {
coordenateList = new ArrayList<>();
}
public ArrayList<Coordenate> getCoordenateList() {
return coordenateList;
}
public Coordenate getCoordenateByKey(String keyID) {
for (Coordenate c : coordenateList) {
if (c.getKeyID().equals(keyID)) {
return c;
}
}
return null;
}
public boolean addCoordenate(Coordenate c) {
if (!coordenateList.contains(c)) {
return coordenateList.add(c);
}
return false;
}
public boolean removeCoordenate(Coordenate c){
if (coordenateList.contains(c)) {
return coordenateList.remove(c);
}
return false;
}
}
Once again, I'm sorry for the huge code, but I really want to give as much info as I possibly can. Any questions or doubts, feel free to ask.
If you were getting a StackOverFlow error when compiling your code, then you would have found a bug in your compiler. But you are definitely not receiving a StackOverFlow error when compiling your code, you are receiving it when running your code.
(Recursion is an advanced computer science topic, but if you are still struggling with concepts like when you are compiling your program and when you are running it, then recursion might be a bit too advanced for you right now. Just a thought.)
In your solver2() function you have a monstrous nested if() statement which will always recurse except for a certain unlikely set of circumstances.
Then, you have another sequence of if()-else statements which will also always recurse unless none of the tested conditions is true.
I do not think anyone will invest all the time necessary to read and make sense out of this monstrosity that you have there, so the only recommendation that can be made is to add more conditions in your recursive function which will make it far more likely to refrain from recursing at some point, so that your recursive function will not keep recursing forever. (That is, until it runs out of stack.)

The values in the if statement is not returning, only returning the else statement (can't run it in the main class)

This subclass won't go through the if statements but only return the else statement so it only returns 0. Also, the main class and subclass are separate java classes.
public class LargestEven {
int largestEven(int x, int y, int z) {
if(x % 2 == 0 && x >= y && x >= z) {
return x; // this part won't return
}
if(y % 2 == 0 && y >= x && y >= z) {
return y; //this part also won't return
}
if(z % 2 ==0 && z >= x && z >= y) {
return z; //this too won't return
}
else {
return 0;
}
}
}
Your code requires that a number is both the largest and even. In your example with values (2, 4, 9), you will not get back 4, because 4 is the largest even between these numbers, but not the largest, i.e. this is not true: y>=z.
You would need to change your checks, so that you only check the valid cases:
public class LargestEven {
int largestEven(int x, int y, int z) {
boolean xIsEven = x%2 == 0;
boolean yIsEven = y%2 == 0;
boolean zIsEven = z%2 == 0;
//checks that x is even and greater from y and z if y and z are
//even respectively
if (xIsEven && (!yIsEven || x>=y) && (!zIsEven || x >= z)) {
return x; // this part won't return
}
//we know for sure that x is not the largest even
//so we skip checking it
if (yIsEven && (!zIsEven || y>=z)) {
return y;
}
//we know that neither x or y are the largest evens
//so return either z if z is even, or 0
return zIsEven ? z : 0;
}
}
It does not appear to be an issue with your function logic... see below, the same function in JS.
function largestEven(x, y, z) {
if (x % 2 == 0 && x >= y && x >= z) {
return x; // this part won't return
}
if (y % 2 == 0 && y >= x && y >= z) {
return y;
}
if (z % 2 == 0 && z >= x && z >= y) {
return z;
} else {
return 0;
}
}
var ele = document.getElementById("result");
ele.innerHTML += "<p>Sending 2, 3, 4 (position z): " + largestEven(2,3,4)+"</p>";
ele.innerHTML += "<p>Sending 3, 4, 2 (position y): " + largestEven(3,4,2)+"</p>";
ele.innerHTML += "<p>Sending 4, 3, 2 (position x): " + largestEven(4,3,2)+"</p>";
ele.innerHTML += "<p>Sending 2, 2, 2 (position x): " + largestEven(2,2,2)+"</p>";
ele.innerHTML += "<p>Sending 3, 3, 3 (no largest): " + largestEven(3,3,3)+"</p>";
<div id="result"></div>

StackOverflowError during recursive calls to find closest empty index in 2D array

I am trying to use a recursive approach to figure out the closest empty element in my 2D array if the input index already has an element. For example, I call my method tryPlant(int X, int Y) to put a symbol in my 2D (32x32) array:
ecoArray[X][Y] == "." (empty) then fill it with "~"
If there is an element besides ".", then recursively find the next empty spot in the same row first, then column.
The code for the method is:
public void tryPlant(int X, int Y){
if (this.ecoArray[X][Y] == ".") {
this.ecoArray[X][Y] = "~";
}else{
if((Y - 1) >= 0) {
tryPlant(X, Y - 1);
}
else if((Y + 1) <= 32){
tryPlant(X, Y + 1);
}else if((X - 1) >= 0 ) {
tryPlant(X - 1, Y);
}else if((X + 1) <= 32){
tryPlant(X + 1, Y);
}
}
}
I am calling the method in another class like this:
Plant p1;
private void initPlants(){
int size = p1.initPop;
for (int i = 0; i < size; i++) {
int randX = randGen();
int randY = randGen();
Plant plant = new Plant(randX, randY, this.ecoArray);
}
}
The randGen() method returns a random integer between 0-31.
Sometimes the random generator gives me indexes such that they do not collide with other objects. An example of this (the | are obstacles):
I want to know why I get a stackoverflow error and what I can do to fix it. If you need any other portions of my code, please ask. I am pretty new to Java.
Edit
public static int left = 0;
public static int right = 0;
public void tryPlant(int X, int Y){
if (this.ecoArray[X][Y] == ".") {
this.ecoArray[X][Y] = "~";
}else{
if((Y - 1) >= 0) {
this.left++;
tryPlant(X, Y - 1);
}
else if((Y + this.left + 1) <= 32){
tryPlant(X, Y + this.left + 1);
this.left = 0;
}else if((X - 1) >= 0 ) {
this.right++;
tryPlant(X - 1, Y);
}else if((X + this.right + 1) <= 32){
tryPlant(X + + this.right + 1, Y);
this.right = 0;
}
}
}
Approximately what happens is: Each time a function is called it is stored in a memory stack. When the function return, what was stored is cleared. But, if you call too many functions, you fullfil the memory and a stackoverflow error is sent.
You get a stackoverflow error because somewhere you have a loop in your algorithm. That cause too many call to tryPlant().
First, when you find a way where you already pass, return. (where char == '~')
Second, where there is an obstacle, return. (where char == '|')
Third, you don't try all directions:
if ((Y - 1) >= 0) {
this.left++;
tryPlant(X, Y - 1);
} else if ((Y + this.left + 1) <= 32){
tryPlant(X, Y + this.left + 1);
this.left = 0;
} else if ((X - 1) >= 0 ) {
this.right++;
tryPlant(X - 1, Y);
} else if ((X + this.right + 1) <= 32){
tryPlant(X + + this.right + 1, Y);
this.right = 0;
}
I tried this and it seems to work:
public class Test {
private char[][] ecoArray;
public Test() {
String[] stringArray = new String[] {
"||.|.||..|..||.|.||||||||..||.||",
"||||....||..|||..||....|.||..|||",
"||||||...|.|||...||.|..||..||||.",
"||...||.|.|||.||||.|||||.|...||.",
"|.|....|.|||||||||..||.|.|.||...",
"..|||.||||...|..||.||..|..||||.|",
"..|.||||||..||.||||..|||.|.|...|",
"|||||.||.|||...||...||..||.|||..",
"||||.|..||||||..|.|||...||.||.|.",
"|||.|||||.|||||.||||.|....||||||",
"||...||||||.|.|||||||||||.|.|.||",
"|.|.||||||||.||||....|.||||.||||",
"||..||.||||.|..||.|||..||.|.||||",
"..||..|..||.|.|||..|||..|||||.|.",
"||||.|.||.||||.|||||..|||.|.....",
"..|.|.|||..|||..||.||||.|||.|..|",
"||||.|..|||||||.|||||.||.|.|....",
"..|...||...|||||.|...|..|...|||.",
"..|||||||..||...||||||..|..|||||",
"||||..||.|.|||||.||||.|||||.||..",
"|||||.||||.|....||||....||.||...",
"||..||.|||||.||||||..||..|....||",
"|.||||.||..|...|.|..|||.|.|||.||",
"...||||.|..|||.|||..|.||...|.|||",
".||||.|..|.|..||..||..||..||||||",
"|||.|||..|||..||||.||||.|.||.|||",
"|||||.||...|.|.|.||...|||..|.|||",
".||||.|.|.|||...|||.|||.....||||",
"|||.|||.|.|...||.|....||||.|.|||",
".||||||.|||||||...||..|||.||||.|",
"||||.|||||.|.||.||||..|.|||.||||",
"|.|.||||....|.||||||||.|||||.|.|"
};
this.ecoArray = new char[32][32];
int index = 0;
for (String s : stringArray) {
this.ecoArray[index] = s.toCharArray();
++index;
}
}
public void tryPlant(int X, int Y){
if (this.ecoArray[X][Y] == '~' || this.ecoArray[X][Y] == '|') {
return;
}
if (this.ecoArray[X][Y] == '.') {
this.ecoArray[X][Y] = '~';
if ((Y - 1) >= 0) {
tryPlant(X, Y - 1);
}
if((Y + 1) < 32){
tryPlant(X, Y + 1);
}
if((X - 1) >= 0 ) {
tryPlant(X - 1, Y);
}
if((X + 1) < 32){
tryPlant(X + 1, Y);
}
}
}
private void displayInConsole() {
for (char[] cl : this.ecoArray) {
System.out.println(cl);
}
}
public static void main(String[] args) {
for (int x = 0; x < 32; x++) {
for (int y = 0; y < 32; y++) {
Test t = new Test();
t.tryPlant(x, y);
System.out.println("After tryPlant('" + x + "','" + y + "'): ");
t.displayInConsole();
}
}
}
}
Is it doing what you need ? I don't really understand where you want to start and where you want to stop...
The result is too big sorry...

Categories