2016-12-06 43 views
3

我正在执行代码来查找两个节点之间的最短路径,但是 为什么当我更改DFS函数的第一行时,输出也发生了变化。 这不是真的吗添加到列表类实例

path += [start]相当于path = path + [start]

改变之前的输出是::

Current DFS path: 0 
Current DFS path: 0->1 
Current DFS path: 0->1->2 
Current DFS path: 0->1->2->3 
Current DFS path: 0->1->2->3->4 
Current DFS path: 0->1->2->3->5 
Current DFS path: 0->1->2->4 
Current DFS path: 0->2 
Current DFS path: 0->2->3 
Current DFS path: 0->2->3->1 
Current DFS path: 0->2->3->4 
Current DFS path: 0->2->3->5 
Current DFS path: 0->2->4 
shortest path is 0->2->3->5 

改变后::

Current DFS path: 0 
Current DFS path: 0->1 
Current DFS path: 0->1->2 
Current DFS path: 0->1->2->3 
Current DFS path: 0->1->2->3->4 
Current DFS path: 0->1->2->3->4->5 
shortest path is 0->1->2->3->4->5 

代码::

class Node(object): 
    def __init__(self, name): 
     """Assumes name is a string""" 
     self.name = name 
    def getName(self): 
     return self.name 
    def __str__(self): 
     return self.name 

class Edge(object): 
    def __init__(self, src, dest): 
     """Assumes src and dest are nodes""" 
     self.src = src 
     self.dest = dest 
    def getSource(self): 
     return self.src 
    def getDestination(self): 
     return self.dest 
    def __str__(self): 
     return self.src.getName() + '->' + self.dest.getName() 

class WeightedEdge(Edge): 
    def __init__(self, src, dest, weight = 1.0): 
     """Assumes src and dest are nodes, weight a number""" 
     self.src = src 
     self.dest = dest 
     self.weight = weight 
    def getWeight(self): 
     return self.weight 
    def __str__(self): 
     return self.src.getName() + '->(' + str(self.weight) + ')'\ 
       + self.dest.getName() 

#Figure 12.8 
class Digraph(object): 
    #nodes is a list of the nodes in the graph 
    #edges is a dict mapping each node to a list of its children 
    def __init__(self): 
     self.nodes = [] 
     self.edges = {} 
    def addNode(self, node): 
     if node in self.nodes: 
      raise ValueError('Duplicate node') 
     else: 
      self.nodes.append(node) 
      self.edges[node] = [] 
    def addEdge(self, edge): 
     src = edge.getSource() 
     dest = edge.getDestination() 
     if not (src in self.nodes and dest in self.nodes): 
      raise ValueError('Node not in graph') 
     self.edges[src].append(dest) 
    def childrenOf(self, node): 
     return self.edges[node] 
    def hasNode(self, node): 
     return node in self.nodes 
    def __str__(self): 
     result = '' 
     for src in self.nodes: 
      for dest in self.edges[src]: 
       result = result + src.getName() + '->'\ 
         + dest.getName() + '\n' 
     return result[:-1] #omit final newline 

class Graph(Digraph): 
    def addEdge(self, edge): 
     Digraph.addEdge(self, edge) 
     rev = Edge(edge.getDestination(), edge.getSource()) 
     Digraph.addEdge(self, rev) 

#Figure 12.9 
def printPath(path): 
    """Assumes path is a list of nodes""" 
    result = '' 
    for i in range(len(path)): 
     result = result + str(path[i]) 
     if i != len(path) - 1: 
      result = result + '->' 
    return result 

def DFS(graph, start, end, path, shortest, toPrint = False): 
    """Assumes graph is a Digraph; start and end are nodes; 
      path and shortest are lists of nodes 
     Returns a shortest path from start to end in graph""" 
    path = path + [start] 
    if toPrint: 
     print('Current DFS path:', printPath(path)) 
    if start == end: 
     return path 
    for node in graph.childrenOf(start): 
     if node not in path: #avoid cycles 
      if shortest == None or len(path) < len(shortest): 
       newPath = DFS(graph, node, end, path, shortest, 
           toPrint) 
       if newPath != None: 
        shortest = newPath 
    return shortest 

def shortestPath(graph, start, end, toPrint = False): 
    """Assumes graph is a Digraph; start and end are nodes 
     Returns a shortest path from start to end in graph""" 
    return DFS(graph, start, end, [], None, toPrint) 

#Figure 12.10 
def testSP(): 
    nodes = [] 
    for name in range(6): #Create 6 nodes 
     nodes.append(Node(str(name))) 
    g = Digraph() 
    for n in nodes: 
     g.addNode(n) 
    g.addEdge(Edge(nodes[0],nodes[1])) 
    g.addEdge(Edge(nodes[1],nodes[2])) 
    g.addEdge(Edge(nodes[2],nodes[3])) 
    g.addEdge(Edge(nodes[2],nodes[4])) 
    g.addEdge(Edge(nodes[3],nodes[4])) 
    g.addEdge(Edge(nodes[3],nodes[5])) 
    g.addEdge(Edge(nodes[0],nodes[2])) 
    g.addEdge(Edge(nodes[1],nodes[0])) 
    g.addEdge(Edge(nodes[3],nodes[1])) 
    g.addEdge(Edge(nodes[4],nodes[0])) 
    sp = shortestPath(g, nodes[0], nodes[5]) 
    print('Shortest path found by DFS:', printPath(sp)) 

注::这个代码是从这本书enter link description here

+1

的[?为什么+ =意外行为上的列表]可能的复制(http://stackoverflow.com/questions/2347265/why-does-behave-unexpectedly- on-lists) –

回答

3

他们是不一样的

path += [start]相当于path.extend([start]) - 它变异path

在另一方面

path = path + [start]创建一个新的列表并将其命名为start

考虑下面的实验,并记下编号:

>>> a = [1] 
>>> id(a) 
55937672 
>>> a += [2,3] 
>>> id(a) 
55937672 
>>> b = [1] 
>>> id(b) 
55930440 
>>> b = b + [1,2] 
>>> id(b) 
55937288 

b改变的ID但a的ID没有。

至于为什么它使你的代码有所不同 - DFS是一个函数。在使用path += [start]的版本中,您正在修改传递的参数path - 并且此修改在调用返回后仍然存在。另一方面,在使用path = path + [start]的版本中,您正在创建一个名为path的新本地变量,该变量在调用返回时超出了范围,而对参数path没有任何更改。

+0

这是否意味着使用'a = a + something'比使用'a + = something'来避免意外的错误...? –

+1

@JafarAbdi它取决于你想要做什么。如果你想*修改原始列表,然后使用'a + = something',但是如果你想得到一个新列表,然后使用'a = a + something'。如果您遇到无关紧要的情况,我会选择'a + = something',因为它会提高内存使用效率。另一方面,在某些情况下,修改列表的副作用是不受欢迎的(因为它可能会以不想要的方式影响调用者的环境),在这种情况下使用'a = a + something'。 –

0

在行

path=path+[start] 

你创建新的列表对象。

在行

path+=[start] 

修改已经存在的列表对象。

你可以试试这个:

path2=path[:] 
path2+=[start]