交叉操作后列表仅保留最后两个Chromosome的问题求助
遗传算法交叉操作:列表仅保留最后两个Chromosome的问题解决
嘿,我仔细瞅了你的代码,终于找到问题所在了!你每次循环生成新Chromosome时,虽然看起来是创建了新的对象,但实际上所有Chromosome都共享了同一个数组引用——因为newGenes1和newGenes2是在for循环外面定义的。
每次循环你只是修改这两个数组里的元素值,而不是创建新的数组。当你把这两个数组传给Chromosome构造函数时,所有生成的Chromosome对象都会指向这两个数组的内存地址。循环结束后,数组里存的是最后一次循环修改的值,所以你查看整个列表时,所有元素看起来都是最后生成的那两个Chromosome。
解决方法很简单:把数组定义移到循环内部
每次循环都创建新的数组实例,这样每个Chromosome都会持有独立的数组引用,不会互相覆盖。修改后的代码如下:
public Population crossoverChromosomes(Population population, List<Item> items, int capacityOfKnapsack) { Random rand = new Random(); List<Chromosome> chromosomeList = new ArrayList<>(population.getChromosomeList()); int genesLength = population.chromosomeList.get(0).getGenes().length; ArrayList<Chromosome> newCrossoverPopulation = new ArrayList<>(); for (int j = 0; j < population.getPopulationSize() / 2; j++) { // 把数组定义移到循环内部,每次循环创建新数组 int newGenes1[] = new int[genesLength]; int newGenes2[] = new int[genesLength]; int firstChrIndex = rand.nextInt(population.getPopulationSize()); int secondChrIndex = rand.nextInt(population.getPopulationSize()); int d = rand.nextInt(genesLength); // 这里建议改用基因长度,避免超出数组索引范围 Chromosome firstChr = chromosomeList.get(firstChrIndex); Chromosome secondChr = chromosomeList.get(secondChrIndex); for (int i = 0; i < genesLength; i++) { if (i < d) { newGenes1[i] = firstChr.getGenes()[i]; newGenes2[i] = secondChr.getGenes()[i]; } else { newGenes1[i] = secondChr.getGenes()[i]; newGenes2[i] = firstChr.getGenes()[i]; } } Chromosome chr1 = new Chromosome(genesLength, newGenes1); Chromosome chr2 = new Chromosome(genesLength, newGenes2); chr1.fitnessCalculate(items, capacityOfKnapsack); newCrossoverPopulation.add(chr1); chr2.fitnessCalculate(items, capacityOfKnapsack); newCrossoverPopulation.add(chr2); } return new Population(newCrossoverPopulation.size(), newCrossoverPopulation); }
额外小优化
我还帮你调整了两个小细节:
- 生成索引时改成
rand.nextInt(population.getPopulationSize()),这样能取到种群的最后一个元素(原代码会永远跳过最后一个索引) - 交叉点
d改用基因长度作为范围,避免出现d大于基因长度导致数组越界的问题
内容的提问来源于stack exchange,提问作者senham
相关产品推荐
相关产品推荐

