I am working on a cube solver at the moment and it uses breadth first search to find the shortest solution to the 2x2x2 rubiks cube solver. The thing is that in the search there are duplicate positions that get hit and my goal is to know how many of them I have and "prune" them out later.(I know how to avoid the duplicates but that is irrelevant to this post). Here is what it should look like
That is from an old version of the code which works with the hashCode and equals but I am trying to get the new version to work with it. I think the reason is because in the old version I override equals and hashCode, but in the new one I can't seem to do that because I am no longer comparing objects, rather arrays (that is guess). The current version isn't picking up duplicates due to this. It says there are no duplicates but that is incorrect.
here is what the hashCode and equals is like for the old version which detects duplicates.
private Cube() {
cube = new int[][] {
{ 0, 0, 0, 0 },
{ 1, 1, 1, 1 },
{ 2, 2, 2, 2 },
{ 3, 3, 3, 3 },
{ 4, 4, 4, 4 },
{ 5, 5, 5, 5 }
};
cube = scanCube(cube);
cube = print_cube(cube);
}
private Cube(Cube other) {
cube = new int[other.cube.length][];
for (int i = 0; i < other.cube.length; i++) {
cube[i] = Arrays.copyOf(other.cube[i], other.cube[i].length);
}
}
public boolean isSolved() {
for (int i = 0; i < cube.length; i++) {
for (int k = 1; k < cube[i].length; k++) {
if (cube[i][0] != cube[i][k]) {
return false;
}
}
}
return true;
}
#Override
public boolean equals(Object other) {
return other instanceof Cube && Arrays.deepEquals(((Cube) other).cube, cube);
}
#Override
public int hashCode() {
return Arrays.deepHashCode(cube);
}`
Here is the current version.
public static void main(String[] args) {
int[][] cube = new int[][] {
{ 0, 0, 0, 0 },
{ 1, 1, 1, 1 },
{ 2, 2, 2, 2 },
{ 3, 3, 3, 3 },
{ 4, 4, 4, 4 },
{ 5, 5, 5, 5 }
};
cube = scanCube(cube);
cube = print_cube(cube);
solve(cube);
}
private static boolean isSolved(int [][] cube) {
for (int i = 0; i < cube.length; i++) {
for (int k = 1; k < cube[i].length; k++) {
if (cube[i][0] != cube[i][k]) {
return false;
}
}
}
return true;
}
public static int[][] copyCube(int [][] cube){
int [][] copy = new int [6][4];
for(int i = 0; i < 6; i++ ){
copy[i] = cube[i].clone();
}
return copy;
}
public static boolean equals(int[][] other, int[][] cube) {
return Arrays.deepEquals(other, cube);
}
public int hashCode(int [][] cube) {
return Arrays.deepHashCode(cube);
}
In the search method is where duplicates are determined. Here is the code for the old one.
static public void solve(Cube c) {
Set<Cube> cubesFound = new HashSet<Cube>();
cubesFound.add(c);
Stack<Cube> s = new Stack<Cube>();
s.push(c);
Set<Stack<Cube>> initialPaths = new HashSet<Stack<Cube>>();
initialPaths.add(s);
solve(initialPaths, cubesFound);
}
static public void solve(Set<Stack<Cube>> livePaths, Set<Cube> cubesFoundSoFar) {
System.out.println("livePaths size:" + livePaths.size());
int numDupes = 0;
Set<Stack<Cube>> newLivePaths = new HashSet<Stack<Cube>>();
for (Stack<Cube> currentPath : livePaths) {
Set<Cube> nextStates = currentPath.peek().getNextStates();
for (Cube next : nextStates) {
if (currentPath.size() > 1 && next.isSolved()) {
currentPath.push(next);
System.out.println("Path length:" + currentPath.size());
System.out.println("Path:" + currentPath);
System.exit(0);
} else if (!cubesFoundSoFar.contains(next)) {
Stack<Cube> newCurrentPath = new Stack<Cube>();
newCurrentPath.addAll(currentPath);
newCurrentPath.push(next);
newLivePaths.add(newCurrentPath);
cubesFoundSoFar.add(next);
} else {
numDupes += 1;
}
}
}
System.out.println("Duplicates found " + numDupes + ".");
solve(newLivePaths, cubesFoundSoFar);
}
And the new one.
static private void solve(int[][] cube) {
int[][][] s = new int[12][6][4];
s[0] = cube;
Set<int[][][]> initialPaths = new HashSet<int[][][]>();
initialPaths.add(s);
Set<int[][]> cubesFound = new HashSet<int[][]>();
cubesFound.add(cube);
solve(initialPaths, cubesFound, 1);
}
static private void solve(Set<int[][][]> livePaths,Set<int[][]> cubesFoundSoFar, int iterationCount) {
System.out.println("livePaths size:" + livePaths.size());
Set<int[][][]> newLivePaths = new HashSet<int[][][]>();
int counter = 0;
int recordDepth = 0;
int duplicates = 0;
for(int[][][] currentPath : livePaths) {
Set<int [][]> nextStates = getNextStates(currentPath[iterationCount-1]);
for (int[][] next : nextStates) {
if (isSolved(next)) {
currentPath[iterationCount] = next;
int maxSteps = -1;
System.out.println("Path:" );
for(int i = 0; i < currentPath.length; i++) {
if(currentPath[i] != null) {
maxSteps = i;
System.out.println(toString(currentPath[i]));
}else {
break;
}
}
System.out.println("Path length:" + maxSteps);
System.exit(0);
} else if(!cubesFoundSoFar.contains(next)){
int[][][] newCurrentPath = new int[12][6][4];
newCurrentPath = currentPath.clone();
newCurrentPath[iterationCount] = next;
newLivePaths.add(newCurrentPath);
counter ++;
cubesFoundSoFar.add(next);
} else {
duplicates += 1;
}
}
}
//System.out.println(" Set.size(): "+newLivePaths.size());
String storeStates = "positions.txt";
try {
PrintWriter outputStream = new PrintWriter(storeStates);
outputStream.println(storeStates);
for(int[][][] s:newLivePaths) {
outputStream.println(toString(s[iterationCount]));
}
outputStream.close();
} catch (FileNotFoundException e) {
System.err.println("Fatal: could not open cache file for cube positions. exiting.");
e.printStackTrace();
System.exit(1);
}
System.out.println("Duplicates found "+ duplicates + ".");
solve(newLivePaths, cubesFoundSoFar, iterationCount+1);
}
You have not overridden the equals(Object) method in your second code, but
Set.contains(Object) use equals to compare the elements. Since there is none in Cube, the one of Object is used. This does not compare content, it just test if the objects are the same instance (same memory location).
Here the relevant part of contains:
... More formally, returns true if and only if this set contains an element e such that (o==null ? e==null : o.equals(e)). ...
You could add something like to the second code:
#Override
public boolean equals(Object other) {
if (other instanceof Cube)
return equals(cube, ((Cube) other).cube);
else
return false;
}
#Override
public int hashCode() {
return hashCode(cube);
}
Related
I have to find a missing element from the array where array has got values from <0, N>.
For example: int tablica[] = {0, 1, 2, 3, 5};, missing number is 4.
I have got 3 implementations of this code, but...
Only one gives me output, why?
Why naiveFindMissing() and optimalFindMissing() don't give any output?
public class Zad2_Selftraining {
public static void main(String[] args) {
findMissing();
naiveFindMissing();
optimalFindMissing();
}
public static void findMissing() {
int tablica[] = {0, 1, 2, 3, 5};
for(int i = 0; i<tablica.length;i++ ){
if (tablica[i] != i){
System.out.println("Missing: " + i);
return;
}
}
System.out.println("Everything is correct");
return;
}
private static int naiveFindMissing() {
int array[] = {0,1,2,4,5,6,7};
int missing = 0;
boolean elementFound;
for (int elementToFind = 0; elementToFind <= array.length; elementToFind++) {
elementFound = false;
for (int elementInArray : array) {
if (elementToFind == elementInArray) {
elementFound = true;
break;
}
}
if (!elementFound) {
missing = elementToFind;
break;
}
}
return missing;
}
private static int optimalFindMissing() {
int array[] = {0,1,2,4,5,6,7};
int expectedSum = (array.length + 1) * array.length / 2;
int actualSum = 0;
for (int element : array) {
actualSum += element;
}
return expectedSum - actualSum;
}
}
Because you have System.out.println statement only in first method. The other two methods just return result without printing it
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 2 years ago.
Improve this question
Question:
Write a Number class that can be used to determine if a number is odd, even, or
perfect. Then, use this Number class to determine how many numbers in the list are odd, even, and perfect.
Number Class:
public class Number
{
private Integer number;
public Number(int n)
{
number=n;
}
public boolean isEven()
{
if(number % 2 == 0)
return true;
else
return false;
}
public boolean isOdd()
{
if(number % 2 != 0)
return true;
else
return false;
}
public boolean isPerfect()
{
int count = 0;
for(int i = 1; i<number; i++)
{
if(number % i == 0)
count += i;
}
if(number == count)
{
return true;
}
else
return false;
}
public String toString()
{
return "" +number;
}
}
My number class is running good there is no problem in my Number class. But in my number analyzer class where i find the number of odd,even and perfect.
Number Analyzer class:
public class NumberAnalyzer
{
private ArrayList<Number> list;
public NumberAnalyzer(int l)
{
list=l;
}
public int countOdds()
{
int odd = 0;
for(int i=0; i<list.size(); i++)
{
if(list.isOdd() == true)
return odd++;
}
}
public int countEvens()
{
int even = 0;
for(int x = 0; x<list.size(); x++)
{
if(list.isEven() == true)
return even++;
}
}
public int countPerfects()
{
int perfect = 0;
for(int z = 0; z<list.size(); z++)
{
if(list.isPerfect() == true)
return perfect++;
}
}
public String toString()
{
return "" + list;
}
}
Please make correction on this class so my program run perfectly. I do not understand the problem please make change in this so program work perfectly.
Runner of program:
import static java.lang.System.*;
public class Runner
{
public static void main( String args[] )
{
int[] r = {5, 12, 9, 6, 1, 4, 8, 6 };
NumberAnalyzer test = new NumberAnalyzer(r);
out.println(test);
out.println("odd count = "+test.countOdds());
out.println("even count = "+test.countEvens());
out.println("perfect count = "+test.countPerfects()+"\n\n\n");
}
}
Correct answers with this Runner:
[5, 12, 9, 6, 1, 4, 8, 6]
odd count = 3
even count = 5
perfect count = 2
Thank you
I didn't understand how it could work if it even didn't complile but nevermind. You need to change 2 classes: NumberAnalyzer and Runner. Please have a look:
public class Runner {
public static void main(String args[]) {
Number[] r = {new Number(5), new Number(12), new Number(9), new Number(6),
new Number(1), new Number(4), new Number(8), new Number(6)};
NumberAnalyzer test = new NumberAnalyzer(r);
out.println(test);
out.println("odd count = " + test.countOdds());
out.println("even count = " + test.countEvens());
out.println("perfect count = " + test.countPerfects() + "\n\n\n");
}
}
and
import java.util.Arrays;
import java.util.List;
public class NumberAnalyzer {
private List<Number> list;
public NumberAnalyzer(Number[] l) {
list = Arrays.asList(l);
}
public int countOdds() {
int odd = 0;
for (Number value : list) {
if (value.isOdd() == true) {
odd++;
}
}
return odd;
}
public int countEvens() {
int even = 0;
for (Number value : list) {
if (value.isEven() == true) {
even++;
}
}
return even;
}
public int countPerfects() {
int perfect = 0;
for (Number value : list) {
if (value.isPerfect() == true) {
perfect++;
}
}
return perfect;
}
public String toString() {
return "" + list;
}
}
in that case it returns a correct output.
Your approach for resolving this problem has a lot of problems, especially in NumberAnalyzer class.
1) You should call the isOdd(), isEven() etc. on an element of the list, not on the list itself -> list.get(i).isEven()
2) The return even++ will exit the loop and return 1 if the condition is met, and the method is not even working since you don't have a return statement in case if the if statement from the for loop doesn't get executed.
3) Not a big problem, but the x and z can be declared as i too -> more intuitive ( i ndex)
4) The isPerfect() method is not correct, an easy solution to solve this problem could be using Math.sqrt() and Math.floor()
5) You're trying to pass an int[] array and the constructor expect an int. And after this, you have an ArrayList<Number> inside the NumberAnalyzer class and you're trying to assign to this list an int value.
Solutions:
1) + 2) + 3) :
public class NumberAnalyzer {
private List<Number> list; //Changed the ArrayList<> to List<>
public NumberAnalyzer(List<Number> l) {
list = l;
}
public int countOdds() {
int odd = 0;
for (int i = 0; i < list.size(); i++) {
if (list.get(i).isOdd())
odd++;
}
return odd;
} // SAME FOR THE OTHER METHODS.
}
4)
public boolean isPerfect()
{
int square = Math.sqrt(number);
return (square - Math.floor(square)) == 0;
}
5) The static void main method should now look like this:
Integer[] r = {5, 12, 9, 6, 1, 4, 8, 6};
List<Integer> rList = Arrays.asList(r);
List<Number> numberList = rList.stream().map(Number::new).collect(Collectors.toList());
NumberAnalyzer test = new NumberAnalyzer(numberList);
Write a method to return the Toy that occurs in the list most frequent and another method to sort the toys by count.
This is my code
import java.util.ArrayList;
public class ToyStore {
private ArrayList<Toy> toyList;
public ToyStore() {
}
public void loadToys(String toys) {
toyList = new ArrayList<Toy>();
for (String item : toys.split(" ")) {
Toy t = getThatToy(item);
if (t == null) {
toyList.add(new Toy(item));
} else {
t.setCount(t.getCount() + 1);
}
}
}
public Toy getThatToy(String nm) {
for (Toy item : toyList) {
if (item.getName().equals(nm)) {
return item;
}
}
return null;
}
public String getMostFrequentToy() {
int position = 0;
int maximum = Integer.MIN_VALUE;
for (int i = toyList.size() - 1; i >= 0; i--) {
if (toyList.get(i).getCount() > maximum)
maximum = toyList.get(i).getCount();
position = i;
}
return toyList.get(position).getName();
}
public void sortToysByCount() {
ArrayList<Toy> t = new ArrayList<Toy>();
int count = 0;
int size = toyList.size();
for (int i = size; i > 0; i--) {
t.add(new Toy(getMostFrequentToy()));
t.get(count).setCount(getThatToy(getMostFrequentToy()).getCount());
toyList.remove(getThatToy(getMostFrequentToy()));
count++;
}
toyList = t;
}
public String toString() {
return toyList + "" + "\n" + "max == " + getMostFrequentToy();
}
}
Here is the method I care about
public void sortToysByCount() {
ArrayList<Toy> t = new ArrayList<Toy>();
int count = 0;
int size = toyList.size();
for (int i = size; i > 0; i--) {
t.add(new Toy(getMostFrequentToy()));
t.get(count).setCount(getThatToy(getMostFrequentToy()).getCount());
toyList.remove(getThatToy(getMostFrequentToy()));
count++;
}
toyList = t;
}
Here is my output
[sorry 4, bat 1, train 2, teddy 2, ball 2]
Here is what I want
[sorry 4, train 2, teddy 2, ball 2, bat 1];
What is wrong in my code? How do I do it?
The problem is in your getMostFrequentToy() method:
Replace
if (toyList.get(i).getCount() > maximum)
maximum = toyList.get(i).getCount();
position = i;
with
if (toyList.get(i).getCount() > maximum) {
maximum = toyList.get(i).getCount();
position = i;
}
because you want to get the position that corresponds to that maximum.
You have some in-efficiencies in your code. Every single time you call getMostFrequentToy(), you are iterating over the whole list, which may be fine as you are constantly removing objects, but you really don't need to make new Toy objects for those that already exist in the list.
So, this is "better", but still not sure you need to getThatToy when you should already know which one is the most frequent.
String frequent;
for (int i = size; i > 0; i--) {
frequent = getMostFrequentToy();
t.add(new Toy(frequent));
t.get(count).setCount(getThatToy(frequent).getCount());
toyList.remove(getThatToy(frequent));
count++;
}
Anyways, I think the instructions asked you to return the Toy object, not its name.
It's quite simple, just keep track of the max count.
public Toy getMostFrequentToy() {
Toy mostFrequent = null;
int maximum = Integer.MIN_VALUE;
for (Toy t : toyList) {
if (t.getCount() > maximum)
mostFrequent = t;
}
return t;
}
Now, the above code can become
public void sortToysByCount() {
ArrayList<Toy> t = new ArrayList<Toy>();
// int count = 0;
int size = toyList.size();
Toy frequent;
for (int i = size; i > 0; i--) {
frequent = getMostFrequentToy();
t.add(frequent);
// t.get(count).setCount(frequent.getCount()); // Not sure about this
toyList.remove(frequent);
// count++;
}
toyList.clear();
toyList.addAll(t);
}
Realistically, though, when you want to sort, you really should see how to create a Comparator for your Toy objects.
I have written a simple genetic algorithm program in java. What it is does is maximize the decimal value represented by the bits in the chromosome. Somehow mutation is not working as expected, e.g. causing two genes to mutate when just one is to change. The print statements I have included there show which to mutate, but in addition to that some more chromosomes get mutated. I can't figure out what the problem is :-(
Here are my java classes.
Gene.java
public class Gene {
private int value;
public Gene() {
value = Math.random() < 0.5 ? 0 : 1;
}
public Gene(int value) {
if (value != 0 && value != 1) {
throw new IllegalArgumentException("value must be either 0 or 1");
}
else {
this.value = value;
}
}
public void mutate() {
value = 1 - value;
}
public int value() {
return value;
}
#Override
public String toString() {
return String.valueOf(value);
}
}
Chromosome.java
import java.util.ArrayList;
import java.util.List;
public class Chromosome implements Comparable {
private ArrayList<Gene> genes;
private final int chromosomeLength;
public Chromosome(int length) {
this.genes = new ArrayList<>();
this.chromosomeLength = length > 0 ? length : 16;
for (int i = 0; i < chromosomeLength; i++) {
this.genes.add(i, new Gene());
}
}
public List<Gene> getAllele(int fromIndex, int toIndex) {
return new ArrayList<>(genes.subList(fromIndex, toIndex));
}
public void setAllele(int fromIndex, List<Gene> allele) {
int lastIndex = fromIndex + allele.size();
if (lastIndex > chromosomeLength) {
throw new IndexOutOfBoundsException("the allele exceeds beyond the size of the chromosome");
}
for (int i = fromIndex, j = 0; i < lastIndex; i++, j++) {
genes.set(i, allele.get(j));
}
}
public int getChromosomeLength() {
return chromosomeLength;
}
public void setGeneAt(int index, Gene gene) {
genes.set(index, gene);
}
public Gene getGeneAt(int index) {
return genes.get(index);
}
public int value() {
return Integer.parseInt(this.toString(), 2);
}
#Override
public String toString() {
StringBuilder chromosome = new StringBuilder("");
genes.stream().forEach((Gene g) -> chromosome.append(g));
return chromosome.toString();
}
#Override
public int compareTo(Object anotherChromosome) {
Chromosome c = (Chromosome) anotherChromosome;
return this.value() - c.value();
}
}
GenePool.java
import java.util.ArrayList;
import java.util.Arrays;
public class GenePool {
private final ArrayList<Chromosome> genePool;
private final int genePoolSize;
private final int chromosomeLength;
private final double crossOverRate;
private final double mutationRate;
private int[] crossPoints;
public GenePool(int numOfChromosome, int chromosomeLength, double crossOverRate, double mutationRate) {
this.genePoolSize = numOfChromosome;
this.chromosomeLength = chromosomeLength > 0 ? chromosomeLength : 16;
this.crossOverRate = crossOverRate;
this.mutationRate = mutationRate;
crossPoints = new int[1];
crossPoints[0] = this.chromosomeLength / 2;
genePool = new ArrayList<>();
for (int i = 0; i < numOfChromosome; i++) {
genePool.add(new Chromosome(chromosomeLength));
}
}
public int getGenePoolSize() {
return genePoolSize;
}
public Chromosome getChromosomeAt(int index) {
return genePool.get(index);
}
public void setChromosomeAt(int index, Chromosome c) {
genePool.set(index, c);
}
public int getChromosomeLength() {
return chromosomeLength;
}
public Chromosome[] crossOver(Chromosome c1, Chromosome c2) {
Chromosome[] offsprings = new Chromosome[2];
offsprings[0] = new Chromosome(c1.getChromosomeLength());
offsprings[1] = new Chromosome(c1.getChromosomeLength());
Chromosome[] parentChromosomes = {c1, c2};
int selector = 0;
for (int i = 0, start = 0; i <= crossPoints.length; i++) {
int crossPoint = i == crossPoints.length ? c1.getChromosomeLength() : crossPoints[i];
offsprings[0].setAllele(start, parentChromosomes[selector].getAllele(start, crossPoint));
offsprings[1].setAllele(start, parentChromosomes[1 - selector].getAllele(start, crossPoint));
selector = 1 - selector;
start = crossPoint;
}
return offsprings;
}
public void mutateGenePool() {
int totalGeneCount = genePoolSize * chromosomeLength;
System.out.println("Mutating genes:");
for (int i = 0; i < totalGeneCount; i++) {
double prob = Math.random();
if (prob < mutationRate) {
System.out.printf("Chromosome#: %d\tGene#: %d\n", i / chromosomeLength, i % chromosomeLength);
genePool.get(i / chromosomeLength).getGeneAt(i % chromosomeLength).mutate();
}
}
System.out.println("");
}
public int getLeastFitIndex() {
int index = 0;
int min = genePool.get(index).value();
int currentValue;
for (int i = 1; i < genePoolSize; i++) {
currentValue = genePool.get(i).value();
if (currentValue < min) {
index = i;
min = currentValue;
}
}
return index;
}
public void saveFittest(ArrayList<Chromosome> offsprings) {
// sort in ascending order
offsprings.sort(null);
offsprings.stream().forEach((offspring) -> {
int leastFitIndex = getLeastFitIndex();
if (offspring.value() > genePool.get(leastFitIndex).value()) {
genePool.set(leastFitIndex, offspring);
}
});
}
public void evolve(int noOfGeneration) {
for (int generation = 1; generation <= noOfGeneration; generation++) {
System.out.println("Generation :" + generation);
ArrayList<Integer> selection = new ArrayList<>();
for (int i = 0; i < genePoolSize; i++) {
if (Math.random() <= crossOverRate) {
selection.add(i);
}
}
if (selection.size() % 2 == 1) {
selection.remove(selection.size() - 1);
}
ArrayList<Chromosome> offsprings = new ArrayList<>();
for (int i = 0; i < selection.size(); i += 2) {
int index1 = selection.get(i);
int index2 = selection.get(i + 1);
offsprings.addAll(Arrays.asList(crossOver(genePool.get(index1), genePool.get(index2))));
}
System.out.println("Before saving the offsprings");
displayChromosomes(genePool, "GenePool");
displayChromosomes(offsprings, "Offsprings");
saveFittest(offsprings);
System.out.println("Before mutation:");
displayChromosomes(genePool, "GenePool");
mutateGenePool();
System.out.println("After mutation:");
displayChromosomes(genePool, "GenePool");
System.out.println("\n\n");
}
}
public void displayChromosomes(ArrayList<Chromosome> geneList, String name) {
System.out.println(name);
if (geneList.isEmpty()) {
System.out.println("Empty list");
}
geneList.stream().forEach((c) -> {
System.out.println(c + " -> " + c.value());
});
System.out.println("");
}
}
GADemo.java
public class GADemo {
public static void main(String[] args) {
GenePool gp = new GenePool(6, 8, 0.25, 0.01);
gp.evolve(10);
}
}
After evolving for a number of generations, the chromosomes all tend to become exactly the same, or very similar. And the problem is that that value is not the maximum for that many bits, and sometimes even a small value. For example, for 8 bits the values should (tend to) approach 255, but this doesn't do so in my code. Someone please provide a hint where/how to look for and solve the problem.
Focus on these lines and imagine the references. These are from setAllele()
for (int i = fromIndex, j = 0; i < lastIndex; i++, j++) {
genes.set(i, allele.get(j));
}
You are basically copying the reference from one onto the other. They are the same Gene so whatever mutation you do on those genes, will also affect even other Chromosomes.
You must produce a deep copy here.
Initially each chromosome has an own list of genes. But when you do the crossover operation you set gene objects from one chromosome into the gene list of other chromosome.
When you evolve the system, the number of shared genes will rise and therefore ultimately all chromosomes will share the same genes. No matter how you mutate a gene the chromosomes are not affected.
EDIT:
As Incognito also answered the setAllele method seems to be the culprit where gene sharing starts. You may want to introduce a method in the gene class where you can set its value given another gene.
I have a Jave class that calculates all possible combination for a given array of elements and to do this it uses a recursive method.
It work fine but when the number of input elements raises I found out of memory problem.
What I'd like to do is calculate combinations in chuncks of a given size.
My problem is that I don't know how save and than restore the state for the recursive method,
specially when it the calling depth is high.
Beolw is the code.
Thanks a lot.
package uty;
import java.io.FileOutputStream;
import java.util.ArrayList;
public class ESCalcCombination {
int iMax = 0;
boolean bEnd = false;
int iLenInp;
ArrayList<Integer[]> resultList;
public ESCalcCombination(int[] inElements, int inMaxElem, int inMaxElemLen) {
if (inMaxElem > 0) {
iMax = inMaxElem;
} else {
iMax = new Double(Math.pow(2d, new Integer(inElements.length).doubleValue())).intValue();
}
resultList = new ArrayList(iMax);
iLenInp = inElements.length;
for (int i = 1; i <= iLenInp; i++) {
if (inMaxElemLen > 0) {
if (i > inMaxElemLen) {
break;
}
}
for (int j = 0; j < iLenInp; j++) {
if ((iLenInp - j) < i) {
break;
}
addNextElement(inElements, j, i, null);
if (bEnd) {
break;
}
}
if (bEnd) {
break;
}
}
}
private void addNextElement(int[] inElements, int inCurIndex, int inLimitLen, ArrayList<Integer> inCurrentCombination) {
if (inCurrentCombination != null
&& (inCurrentCombination.size() + (iLenInp - inCurIndex)) < inLimitLen) {
return;
}
ArrayList<Integer> alCombinationLoc = new ArrayList();
if (inCurrentCombination != null) {
alCombinationLoc.addAll(inCurrentCombination);
}
alCombinationLoc.add(inElements[inCurIndex]);
if (alCombinationLoc.size() == inLimitLen) {
Integer[] arComb = new Integer[alCombinationLoc.size()];
arComb = alCombinationLoc.toArray(arComb);
resultList.add(arComb);
alCombinationLoc.clear();
alCombinationLoc = null;
if (resultList.size() == iMax) {
bEnd = true;
}
return;
}
for (int i = ++inCurIndex; i < iLenInp; i++) {
addNextElement(inElements, i, inLimitLen, alCombinationLoc);
if (bEnd) {
return;
}
}
}
public void close() {
ESUty.closeAL(resultList);
}
public ArrayList<Integer[]> getCombinations() {
return resultList;
}
public static void main(String[] args) {
ESCalcCombination ESCaCo = new ESCalcCombination(new int[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, 0, 15);
FileOutputStream fos = null;
try {
fos = new FileOutputStream("c:\\test\\conbinations.txt");
for (int i = 0; i < ESCaCo.getCombinations().size(); i++) {
StringBuilder sb = new StringBuilder();
for (int j = 0; j < ESCaCo.getCombinations().get(i).length; j++) {
sb.append(ESCaCo.getCombinations().get(i)[j]);
}
System.out.println("elemento " + i + " = " + sb.toString());
fos.write((sb.toString() + System.getProperty("line.separator")).getBytes());
}
} catch (Exception ex) {
System.out.println("errore " + ex);
} finally {
ESUty.closeFileOutputStream(fos);
}
System.exit(0);
}
}
With recursion, part of the data is on stack, and stack cannot be saved that easily. If such functionality is required, rewrite everything using while loop together with the Stack or ArrayDeque data structure instead. This allows to save and restore the state without problems.