我在尝试实现一个类似广度优先搜索的I.A.算法来解决水壶问题时遇到了这个问题:
每次我向数组中添加新元素时,它会将数组中的所有元素都变成与新元素相同。
换句话说…
“frontier”数组在每次“jug”函数调用之间会改变其内部的所有元素。
能有人分享一些关于这段代码的见解吗?
(我更担心实现逻辑,所以它没有被优化)
代码如下:
J1SIZE = 3J2SIZE = 4frontier = []explored = []def IsEmpty(array): result = False if len(array) == 0: result = True return result#填满一个水壶def fillJug(tempNode, jug): copyNode = tempNode copyNode = copyNode if jug == 1: copyNode[0] = J1SIZE elif jug == 2: copyNode[1] = J2SIZE print(copyNode) return copyNode#清空一个水壶def emptyJug(tempNode, jug): copyNode = tempNode if jug == 1: copyNode[0] = 0 elif jug == 2: copyNode[1] = 0 print(copyNode) return copyNode#将一个水壶的内容传递给另一个def passJug(tempNode, jug): copyNode = tempNode if jug == 1: copyNode[1] = copyNode.j1 copyNode[0] = 0 if copyNode[1] > J2SIZE: copyNode[1] = J2SIZE elif jug == 2: copyNode[0] = copyNode[1] copyNode[1] = 0 if copyNode[0] > J1SIZE: copyNode[0] = J1SIZE print(copyNode) return copyNode#检查是否找到解决方案def goalTest(goalNode,currentNode): result = False if goalNode == currentNode: result = True return resultdef BFS(start,end,frontier,explored): start_node = start frontier = [start_node] + frontier if goalTest(end,(frontier[0])): print('解决方案:', frontier[0]) exit() #循环开始 while IsEmpty(frontier) == False: tempNode = frontier.pop(0) #生成节点(状态) if tempNode[0] < J1SIZE: newNode = fillJug(tempNode, 1) if newNode not in explored: frontier = [newNode] + frontier print('前沿1: ', frontier) if tempNode[1] < J2SIZE: newNode = fillJug(tempNode, 2) if newNode not in explored: frontier = [newNode] + frontier print('前沿2: ', frontier) if tempNode[0] == J1SIZE: newNode = emptyJug(tempNode, 1) if newNode not in explored: frontier = [newNode] + frontier print('前沿3: ', frontier) if tempNode[1] == J2SIZE: newNode = emptyJug(tempNode, 2) if newNode not in explored: frontier = [newNode] + frontier print('前沿4: ', frontier) if (tempNode[0] > 0) and (tempNode[1] < J2SIZE): newNode = passJug(tempNode, 1) if newNode not in explored: frontier = [newNode] + frontier print('前沿5: ', frontier) if (tempNode[1] > 0) and (tempNode[0] < J1SIZE): new_node = passJug(tempNode, 2) if new_node not in explored: frontier = [new_node] + frontier print('前沿6: ', frontier) print('前沿: ', frontier) print('已探索: ', explored) for node in frontier: if goalTest(end, node): print('解决方案:', frontier[0]) exit() if node not in explored: explored = [node] + exploredBFS([0,0],[0,2],frontier,explored)
修复后的代码:
回答:
我制作了一个更小的代码示例来重现你的错误:
J1SIZE = 3J2SIZE = 4def fillJug(tempNode, jug): copyNode = tempNode copyNode = copyNode if jug == 1: copyNode[0] = J1SIZE elif jug == 2: copyNode[1] = J2SIZE return copyNodefrontier = [[0, 0]]tempNode = frontier.pop(0)newNode = fillJug(tempNode, 1)frontier = [newNode] + frontier # (1)newNode = fillJug(tempNode, 2) # (2)frontier = [newNode] + frontier
问题在于我标记为(1)
的那一行,你将newNode
(它引用与tempNode
相同的对象)设置为frontier
的第一个项目。然后,在我标记为(2)
的那一行,你在fillJug
中更改了tempNode
。所以frontier
中的值发生了变化。具体来说,你让copyNode
引用与tempNode
相同的对象,然后你更改了copyNode
(以及tempNode
)引用的数据。
你应该重新定义copyNode
为
copyNode = tempNode[:]
这将使copyNode
和tempNode
引用内存中的不同对象(具有相同的值)。(另一种选择是将copyNode
设置为copy.copy(tempNode)
,在导入copy
之后。)
所以新的fillJug
将是
def fillJug(tempNode, jug): copyNode = tempNode[:] if jug == 1: copyNode[0] = J1SIZE elif jug == 2: copyNode[1] = J2SIZE return copyNode
同样的修复方法适用于其他Jug
函数。