我正在实施A *算法,以将给定数量的出租车分配给给定数量的客户:
public SearchNode AStarSearch(List<Car> allCars, List<Customer> allCustomers) {
// creates first node
SearchNode firstNode = createFirstNode(allCars, allCustomers);
open.add(firstNode);
SearchNode currentNode;
while(true) {
currentNode = open.poll(); //error thrown here
if (currentNode.allCustomers.isEmpty()) break;
closed.add(currentNode);
SearchNode temp;
Iterator<Customer> itrCus = currentNode.allCustomers.iterator();
Iterator<Car> itrCar = currentNode.allCars.iterator();
while (itrCus.hasNext()) {
Customer currentCustomer = itrCus.next();
while (itrCar.hasNext()) {
Car currentCar = itrCar.next();
temp = new SearchNode(currentNode, currentCar, currentCustomer);
openUpdate(currentNode, temp);
}
}
}
return currentNode;
}
现在对于孩子SearchNode,我要删除该客户已服务的客户。但这只能在搜索节点内部发生。
这是SearchNode类中发生的事情
public class SearchNode implements Comparable<SearchNode> {
List<Car> allCars;
List<Customer> allCustomers;
SearchNode parent;
public SearchNode(SearchNode parent, Car currentCar, Customer currentCustomer) {
// inheriting values from parent search node
this.allCars = parent.allCars;
this.allCustomers = parent.allCustomers;
this.parent = parent;
// now updating this node's values
this.allCustomers.remove(currentCustomer);
}
我检查了一些印刷品,在while(itrCar.hasNext())
的第二次迭代中,父母的allCustomer
列表缺少currentCustomer
。
编辑:我宁愿问:有人可以告诉我为什么我更改了父节点的值吗?可能是因为我不了解整个Java实际上是通过引用传递的。
答案 0 :(得分:4)
您应该创建一个List
的副本,您要从该副本中本地删除客户:
public SearchNode(SearchNode parent, Car currentCar, Customer currentCustomer) {
// inheriting values from parent search node
this.allCars = parent.allCars; // consider making a copy here too
// if required
this.allCustomers = new ArrayList<>(parent.allCustomers); // make a
// copy
this.parent = parent;
// now updating this node's values
this.allCustomers.remove(currentCustomer); // now you can safely
// remove currentCustomer
// without affecting
// parent.allCustomers
}
答案 1 :(得分:0)
所有持有对象(例如列表)的变量本质上都是指针(nitpickers可能不同意确切的术语,但我敢肯定它已经足够接近了)。所以当你说
this.allCustomers = parent.allCustomers
this.allCustomers和parent.allCustomers现在指向同一List对象。然后
this.allCustomers.remove(currentCustomer)
在该列表上运行.remove()...这是父级的allCustomers ...当前正在迭代中。由于列表被修改,因此迭代失败。
为澄清对此问题的评论,“ Java是按值传递100%。对对象的引用是按值传递”。意味着您不能从C语言 [1] 实现函数“交换”,因为该函数获取指针/引用的副本(值)并且不能更改原始值,但是函数可以修改给出其指针/引用的对象的属性,并使那些传入该对象的调用者可以看到那些修改,因为它们引用的是同一对象。基本类型(int,布尔值等)按值传递,但它们是不可变的(可以说x = 3,然后x = 5,但是没有3.changeValueTo(5)),因此,可以忽略大部分差异。
···
[1]:禁止使用Unsafe类,该类可以直接访问内存。不要使用它,因为它可能会严重损坏东西。能够很好地使用它的聪明工程师(例如Java内部人员有时会使用它)无论如何都不需要我的建议。