如何修改 ArrayList 中与其他对象具有相似值的对象值
How to modify an object value in ArrayList that has value similar to the other objects
我想修改我的 ArrayList 对象(我们称它为 myObject ),它与 ArrayList 中的其他对象具有相似的值。
问题是,当我修改 myObject 时,结果发现具有相似值的其他对象也会被修改。
这个问题的可能原因是什么?
你的回答对我有很大帮助。
哦,我正在研究由 3 类 { Genetic_Controller、染色体、Fitness_Function } 组成的遗传算法,我认为这个问题出现在 "MutateAtPopulationScale" 过程中在 Genetic_Controller.
这是我的源代码:
Genetic_Controller
package AG;
import java.text.DecimalFormat;
import java.util.Random;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
public class Genetic_Controller {
public ArrayList<Chromosome> ChromosomeArray; //arraylist containing some Chromosome
private int popSize; // starting number of antibodies
private double pc; // crossover probability
private double pm; // mutation probability
private int maxGen; // maximal reach of generation
private double optimumPrice;
Random r = new Random();
DecimalFormat df = new DecimalFormat("#,###,###,##0");
public Genetic_Controller(int popSize,double pm, int maxGen) {
this.ChromosomeArray = new ArrayList();
this.popSize = popSize;
this.pm = pm;
this.maxGen = maxGen;
}
public double getOptimumPrice() {
return optimumPrice;
}
private double[][] pricesData;
private int genLength;
public void goOptimise(double[][] pricesData, int dataSize) {
this.pricesData = pricesData;
this.genLength = dataSize;
GeneratePopulation();
System.out.println();
for (int g = 0; g < maxGen; g++) {
System.out.println("Generation : " + (g + 1));
ChromosomeSelection();
MutateAtPopulationScale();
ReplacedPopulation();
EvaluateAllChromosome();
System.out.println();
}
}
public void GeneratePopulation() {
Chromosome c;
for (int i = 0; i < popSize; i++) {
c = new Chromosome(genLength);
c.evaluate(pricesData);
ChromosomeArray.add(c);
}
}
public void printPopulation(ArrayList ChromosomeArray) {
int count = 0;
for (Iterator<Chromosome> it = ChromosomeArray.iterator(); it.hasNext();) {
Chromosome c = it.next();
System.out.print((count+1)+". ");
for (int i = 0; i < genLength; i++) {
System.out.print(c.gen.get(i) + " ");
}
System.out.print("__ Price : " + (int) (1000000 / c.getFitness()) + " __ Fitness : " + df.format(c.getFitness()));
System.out.println();
count++;
}
}
public void EvaluateAllChromosome() {
for (Iterator<Chromosome> it = this.ChromosomeArray.iterator(); it.hasNext();) {
Chromosome c = it.next();
c.evaluate(pricesData);
}
}
// Chromosome Selection use Roulette Wheel Selection
public void ChromosomeSelection() {
double totFitness = 0;
double[] RelativeFit = new double[popSize];
double[] CumulativeFit = new double[popSize];
double CumulativeMemory = 0;
ArrayList<Chromosome> NewChromosomeArray = new ArrayList();
for (Iterator<Chromosome> it = this.ChromosomeArray.iterator(); it.hasNext();) {
Chromosome c = it.next();
totFitness = totFitness + c.getFitness();
}
int count = 0;
for (Iterator<Chromosome> it = this.ChromosomeArray.iterator(); it.hasNext();) {
Chromosome c = it.next();
RelativeFit[count] = c.getFitness() / totFitness;
CumulativeFit[count] = CumulativeMemory + RelativeFit[count];
CumulativeMemory = CumulativeFit[count];
count++;
}
double[] rand = new double[popSize];
int temp;
for (int i = 0; i < popSize; i++) {
temp = r.nextInt(1 * 100) + (0);
rand[i] = (double) temp / 100;
for (int j = 0; j < popSize; j++) {
if (CumulativeFit[j] <= rand[i] && CumulativeFit[j + 1] > rand[i]) {
NewChromosomeArray.add(i, ChromosomeArray.get(j + 1));
break;
} else if (rand[i] < CumulativeFit[0]) {
NewChromosomeArray.add(i, ChromosomeArray.get(0));
break;
}
}
}
ChromosomeArray.clear();
ChromosomeArray.addAll(NewChromosomeArray);
}
// Function to add new chromosome to population directly proportional to their fitness values.
public void ReplacedPopulation() {
Collections.sort(ChromosomeArray);
// for (int i = ChromosomeArray.size() - 1; i >= popSize; i--) {
// ChromosomeArray.remove(i);
// }
// System.out.println();
System.out.println("Result Of Replaced Population");
printPopulation(ChromosomeArray);
}
public void MutateAtPopulationScale() {
ArrayList<Integer> mutation_index = new ArrayList();
double[] rand = new double[popSize];
int temp;
System.out.println();
System.out.println("Randomize Result for Mutation");
for (int i = 0; i < popSize; i++) {
temp = r.nextInt(1 * 100) + (0);
rand[i] = (double) temp / 100;
System.out.print(rand[i]+" ");
if (rand[i] < pm) {
mutation_index.add(i);
}
}
System.out.println();
System.out.println("Parent Index that occured mutation");
for (int i = 0; i < mutation_index.size(); i++) {
System.out.println(mutation_index.get(i));
}
int gen1, gen2 = -1;
int gen_temp;
System.out.println("Selected Position of Allels");
for (int i = 0; i < mutation_index.size(); i++) {
// Randomly choose 2 allels position
gen1 = r.nextInt(genLength) + (0);
gen2 = r.nextInt(genLength) + (0);
while (gen2 == gen1) {
gen2 = r.nextInt(genLength) + (0);
}
System.out.println("C"+(i+1)+" : "+gen1+" dan "+gen2);
System.out.println("Index : "+i);
ChromosomeArray.get(mutation_index.get(i)).Mutate(gen1, gen2);
}
System.out.println();
EvaluateAllChromosome();
System.out.println("Mutation Results");
printPopulation(ChromosomeArray);
}
}
染色体
package AG;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Random;
public class Chromosome implements Comparable<Chromosome>{
ArrayList<Integer> gen; // xValues
private double fitness;
private static Random rand = new Random();
public ArrayList<Integer> getGen() {
return gen;
}
public double getFitness() {
return fitness;
}
public Chromosome(int size) {
this.gen = new ArrayList<>(size);
RandomizeGen(size);
}
public Chromosome(int size, int nil){
this.gen = new ArrayList<>(size);
for (int i = 0; i < size; i++) {
gen.add(nil);
}
}
public void RandomizeGen(int size) {
for (int i = 1; i <= size; i++) {
gen.add(i);
}
Collections.shuffle(gen);
}
public void evaluate(double[][] prices) {
fitness = AG.Fitness_Function.evaluateFunction(gen,prices);
}
public void Mutate(int genPos1, int genPos2){
int temp;
temp = gen.get(genPos1);
gen.set(genPos1, gen.get(genPos2));
gen.set(genPos2, temp);
}
@Override
public int compareTo(Chromosome c) {
int compareFitness = (int)((Chromosome) c).getFitness();
return compareFitness-(int)this.fitness;
}
}
Fitness_Function
public class Fitness_Function {
public Fitness_Function() {
} //empty constructor
public static double evaluateFunction(ArrayList<Integer> gen, double[][] prices) {
double totalHarga = 0;
double fitness;
for (int j = 0; j < prices.length; j++) {
totalHarga = totalHarga + prices[j][gen.get(j) - 1];
}
fitness = (1 / totalHarga) * 1000000;
return fitness;
}
}
让我举一个实际发生的简单例子:
1 号染色体:1234
2 号染色体:3421(2 和 4 具有相似的值)
3 号染色体:1324
4 号染色体:3421(2 和 4 具有相似的值)
选择了 2 号染色体进行突变 ...
等位基因号选择 1 和 2 进行突变 ...
突变结果 --> Chromosome-2 : 4321
更新人口...
1 号染色体:1234
2 号染色体:4321
3 号染色体:1324
chromosome-4 : 4321 (chromosome-4 也被修改)
我认为可能发生的情况是您实际上并没有创建新的染色体,而是将同一个染色体对象添加了两次。 java 中的对象通过引用创建类似
的对象
NewChromosomeArray.add(0, ChromosomeArray.get(0))
NewChromosomeArray.add(1, ChromosomeArray.get(0))
不创建新对象,而是将 ChromosomeArray 索引 0 的引用添加到 NewChromosomeArray 中的两个位置,因此 NewChromosomeArray 索引 0 处的染色体发生变化也会出现在 NewChromosomeArray 索引 1 处的染色体中,因为它们是相同的染色体刚刚被引用了两次。
确保不再发生这种情况的一种方法是使染色体和不可变对象像本机字符串一样 class。
public class Chromosome implements Comparable<Chromosome>{
ArrayList<Integer> gen; // xValues
private double fitness;
private static Random rand = new Random();
public ArrayList<Integer> getGen() {
return new ArrayList<>(gen);
}
public double getFitness() {
return fitness;
}
public Chromosome(ArrayList<String> gen) {
this.gen = new ArrayList<>(gen);
}
public Chromosome(int size) {
this.gen = new ArrayList<>(size);
RandomizeGen(size);
}
public Chromosome(int size, int nil){
this.gen = new ArrayList<>(size);
for (int i = 0; i < size; i++) {
gen.add(nil);
}
}
public void RandomizeGen(int size) {
for (int i = 1; i <= size; i++) {
gen.add(i);
}
Collections.shuffle(gen);
}
public void evaluate(double[][] prices) {
fitness = AG.Fitness_Function.evaluateFunction(gen,prices);
}
public Chromosome Mutate(int genPos1, int genPos2){
int temp;
ArrayList<Integer> newGen = new ArrayList<>(gen);
temp = newGen.get(genPos1);
newGen.set(genPos1, gen.get(genPos2));
newGen.set(genPos2, temp);
return new Chromosome(newGen)
}
@Override
public int compareTo(Chromosome c) {
int compareFitness = (int)((Chromosome) c).getFitness();
return compareFitness-(int)this.fitness;
}
}
这样你每次改变基因组时都会创建一个新的染色体。
我想修改我的 ArrayList 对象(我们称它为 myObject ),它与 ArrayList 中的其他对象具有相似的值。
问题是,当我修改 myObject 时,结果发现具有相似值的其他对象也会被修改。
这个问题的可能原因是什么? 你的回答对我有很大帮助。
哦,我正在研究由 3 类 { Genetic_Controller、染色体、Fitness_Function } 组成的遗传算法,我认为这个问题出现在 "MutateAtPopulationScale" 过程中在 Genetic_Controller.
这是我的源代码:
Genetic_Controller
package AG;
import java.text.DecimalFormat;
import java.util.Random;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
public class Genetic_Controller {
public ArrayList<Chromosome> ChromosomeArray; //arraylist containing some Chromosome
private int popSize; // starting number of antibodies
private double pc; // crossover probability
private double pm; // mutation probability
private int maxGen; // maximal reach of generation
private double optimumPrice;
Random r = new Random();
DecimalFormat df = new DecimalFormat("#,###,###,##0");
public Genetic_Controller(int popSize,double pm, int maxGen) {
this.ChromosomeArray = new ArrayList();
this.popSize = popSize;
this.pm = pm;
this.maxGen = maxGen;
}
public double getOptimumPrice() {
return optimumPrice;
}
private double[][] pricesData;
private int genLength;
public void goOptimise(double[][] pricesData, int dataSize) {
this.pricesData = pricesData;
this.genLength = dataSize;
GeneratePopulation();
System.out.println();
for (int g = 0; g < maxGen; g++) {
System.out.println("Generation : " + (g + 1));
ChromosomeSelection();
MutateAtPopulationScale();
ReplacedPopulation();
EvaluateAllChromosome();
System.out.println();
}
}
public void GeneratePopulation() {
Chromosome c;
for (int i = 0; i < popSize; i++) {
c = new Chromosome(genLength);
c.evaluate(pricesData);
ChromosomeArray.add(c);
}
}
public void printPopulation(ArrayList ChromosomeArray) {
int count = 0;
for (Iterator<Chromosome> it = ChromosomeArray.iterator(); it.hasNext();) {
Chromosome c = it.next();
System.out.print((count+1)+". ");
for (int i = 0; i < genLength; i++) {
System.out.print(c.gen.get(i) + " ");
}
System.out.print("__ Price : " + (int) (1000000 / c.getFitness()) + " __ Fitness : " + df.format(c.getFitness()));
System.out.println();
count++;
}
}
public void EvaluateAllChromosome() {
for (Iterator<Chromosome> it = this.ChromosomeArray.iterator(); it.hasNext();) {
Chromosome c = it.next();
c.evaluate(pricesData);
}
}
// Chromosome Selection use Roulette Wheel Selection
public void ChromosomeSelection() {
double totFitness = 0;
double[] RelativeFit = new double[popSize];
double[] CumulativeFit = new double[popSize];
double CumulativeMemory = 0;
ArrayList<Chromosome> NewChromosomeArray = new ArrayList();
for (Iterator<Chromosome> it = this.ChromosomeArray.iterator(); it.hasNext();) {
Chromosome c = it.next();
totFitness = totFitness + c.getFitness();
}
int count = 0;
for (Iterator<Chromosome> it = this.ChromosomeArray.iterator(); it.hasNext();) {
Chromosome c = it.next();
RelativeFit[count] = c.getFitness() / totFitness;
CumulativeFit[count] = CumulativeMemory + RelativeFit[count];
CumulativeMemory = CumulativeFit[count];
count++;
}
double[] rand = new double[popSize];
int temp;
for (int i = 0; i < popSize; i++) {
temp = r.nextInt(1 * 100) + (0);
rand[i] = (double) temp / 100;
for (int j = 0; j < popSize; j++) {
if (CumulativeFit[j] <= rand[i] && CumulativeFit[j + 1] > rand[i]) {
NewChromosomeArray.add(i, ChromosomeArray.get(j + 1));
break;
} else if (rand[i] < CumulativeFit[0]) {
NewChromosomeArray.add(i, ChromosomeArray.get(0));
break;
}
}
}
ChromosomeArray.clear();
ChromosomeArray.addAll(NewChromosomeArray);
}
// Function to add new chromosome to population directly proportional to their fitness values.
public void ReplacedPopulation() {
Collections.sort(ChromosomeArray);
// for (int i = ChromosomeArray.size() - 1; i >= popSize; i--) {
// ChromosomeArray.remove(i);
// }
// System.out.println();
System.out.println("Result Of Replaced Population");
printPopulation(ChromosomeArray);
}
public void MutateAtPopulationScale() {
ArrayList<Integer> mutation_index = new ArrayList();
double[] rand = new double[popSize];
int temp;
System.out.println();
System.out.println("Randomize Result for Mutation");
for (int i = 0; i < popSize; i++) {
temp = r.nextInt(1 * 100) + (0);
rand[i] = (double) temp / 100;
System.out.print(rand[i]+" ");
if (rand[i] < pm) {
mutation_index.add(i);
}
}
System.out.println();
System.out.println("Parent Index that occured mutation");
for (int i = 0; i < mutation_index.size(); i++) {
System.out.println(mutation_index.get(i));
}
int gen1, gen2 = -1;
int gen_temp;
System.out.println("Selected Position of Allels");
for (int i = 0; i < mutation_index.size(); i++) {
// Randomly choose 2 allels position
gen1 = r.nextInt(genLength) + (0);
gen2 = r.nextInt(genLength) + (0);
while (gen2 == gen1) {
gen2 = r.nextInt(genLength) + (0);
}
System.out.println("C"+(i+1)+" : "+gen1+" dan "+gen2);
System.out.println("Index : "+i);
ChromosomeArray.get(mutation_index.get(i)).Mutate(gen1, gen2);
}
System.out.println();
EvaluateAllChromosome();
System.out.println("Mutation Results");
printPopulation(ChromosomeArray);
}
}
染色体
package AG;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Random;
public class Chromosome implements Comparable<Chromosome>{
ArrayList<Integer> gen; // xValues
private double fitness;
private static Random rand = new Random();
public ArrayList<Integer> getGen() {
return gen;
}
public double getFitness() {
return fitness;
}
public Chromosome(int size) {
this.gen = new ArrayList<>(size);
RandomizeGen(size);
}
public Chromosome(int size, int nil){
this.gen = new ArrayList<>(size);
for (int i = 0; i < size; i++) {
gen.add(nil);
}
}
public void RandomizeGen(int size) {
for (int i = 1; i <= size; i++) {
gen.add(i);
}
Collections.shuffle(gen);
}
public void evaluate(double[][] prices) {
fitness = AG.Fitness_Function.evaluateFunction(gen,prices);
}
public void Mutate(int genPos1, int genPos2){
int temp;
temp = gen.get(genPos1);
gen.set(genPos1, gen.get(genPos2));
gen.set(genPos2, temp);
}
@Override
public int compareTo(Chromosome c) {
int compareFitness = (int)((Chromosome) c).getFitness();
return compareFitness-(int)this.fitness;
}
}
Fitness_Function
public class Fitness_Function {
public Fitness_Function() {
} //empty constructor
public static double evaluateFunction(ArrayList<Integer> gen, double[][] prices) {
double totalHarga = 0;
double fitness;
for (int j = 0; j < prices.length; j++) {
totalHarga = totalHarga + prices[j][gen.get(j) - 1];
}
fitness = (1 / totalHarga) * 1000000;
return fitness;
}
}
让我举一个实际发生的简单例子:
1 号染色体:1234
2 号染色体:3421(2 和 4 具有相似的值)
3 号染色体:1324
4 号染色体:3421(2 和 4 具有相似的值)
选择了 2 号染色体进行突变 ...
等位基因号选择 1 和 2 进行突变 ...
突变结果 --> Chromosome-2 : 4321
更新人口...
1 号染色体:1234
2 号染色体:4321
3 号染色体:1324
chromosome-4 : 4321 (chromosome-4 也被修改)
我认为可能发生的情况是您实际上并没有创建新的染色体,而是将同一个染色体对象添加了两次。 java 中的对象通过引用创建类似
的对象NewChromosomeArray.add(0, ChromosomeArray.get(0))
NewChromosomeArray.add(1, ChromosomeArray.get(0))
不创建新对象,而是将 ChromosomeArray 索引 0 的引用添加到 NewChromosomeArray 中的两个位置,因此 NewChromosomeArray 索引 0 处的染色体发生变化也会出现在 NewChromosomeArray 索引 1 处的染色体中,因为它们是相同的染色体刚刚被引用了两次。
确保不再发生这种情况的一种方法是使染色体和不可变对象像本机字符串一样 class。
public class Chromosome implements Comparable<Chromosome>{
ArrayList<Integer> gen; // xValues
private double fitness;
private static Random rand = new Random();
public ArrayList<Integer> getGen() {
return new ArrayList<>(gen);
}
public double getFitness() {
return fitness;
}
public Chromosome(ArrayList<String> gen) {
this.gen = new ArrayList<>(gen);
}
public Chromosome(int size) {
this.gen = new ArrayList<>(size);
RandomizeGen(size);
}
public Chromosome(int size, int nil){
this.gen = new ArrayList<>(size);
for (int i = 0; i < size; i++) {
gen.add(nil);
}
}
public void RandomizeGen(int size) {
for (int i = 1; i <= size; i++) {
gen.add(i);
}
Collections.shuffle(gen);
}
public void evaluate(double[][] prices) {
fitness = AG.Fitness_Function.evaluateFunction(gen,prices);
}
public Chromosome Mutate(int genPos1, int genPos2){
int temp;
ArrayList<Integer> newGen = new ArrayList<>(gen);
temp = newGen.get(genPos1);
newGen.set(genPos1, gen.get(genPos2));
newGen.set(genPos2, temp);
return new Chromosome(newGen)
}
@Override
public int compareTo(Chromosome c) {
int compareFitness = (int)((Chromosome) c).getFitness();
return compareFitness-(int)this.fitness;
}
}
这样你每次改变基因组时都会创建一个新的染色体。