提前为漫长的帖子道歉,并感谢任何有时间看一看的人。完成后的完整工作示例。
我想帮助理解代码的行为。我写了两个简单的面向图的类,一个用于节点,另一个用于图本身。该图有一个字典,用于根据节点index
,self.nodes
跟踪节点的实例,节点保留邻居列表self.neighbors
(这些self's
用于{分别为{1}}和Graph
。
奇怪的是,我总是可以通过Node
实例Graph
字典获得节点邻居的完整列表,但如果我试图通过另一个节点访问节点来获取邻居的邻居节点的nodes
列表,我经常得到一个没有邻居的节点,显示不正确的信息。例如,一旦我读入并处理图形,我就可以通过调用neighbors
实例的Graph
来完美地打印出每个节点及其邻居,这给出了一个示例图:
listNodes()
因此,当我直接从图形实例中的self.nodes字典访问节点时,我可以访问节点的邻居。但是,我无法通过节点的邻居列表访问节点邻居的邻居。例如,当我运行(i = 1, neighbors: 5 2 4 3)
(i = 2, neighbors: 1)
(i = 3, neighbors: 1 8 9)
(i = 4, neighbors: 1 9 6)
(i = 5, neighbors: 1)
(i = 6, neighbors: 4 7)
(i = 7, neighbors: 6)
(i = 8, neighbors: 3)
(i = 9, neighbors: 4 3)
时,执行方式如下:
printNeighborsNeighbors(3)
这是输出:
def printNeighborsNeighbors(self, start_num):
node = self.nodes[start_num]
print(node.neighbors)
这表明节点1和9具有零邻居,但这完全错误。该图如下所示:
以下是邻居输入的顺序:
[(i = 1, neighbors: ), (i = 8, neighbors: 3), (i = 9, neighbors: )]
以下是类实现:
5 1
1 2
1 4
1 3
3 8
4 9
3 9
4 6
6 7
和
class Node:
def __init__(self, i):
self.index = i
self.neighbors = []
def createNeighbor(self, neighbor):
self.neighbors.append(neighbor)
def __str__(self):
neighbors = [str(n.index) for n in self.neighbors]
return "(i = %d, neighbors: %s)"%(self.index, " ".join(neighbors))
def __repr__(self):
return str(self)
这就是我的想法:
class Graph:
def __init__(self):
self.nodes = defaultdict(lambda: False)
def neighborNodes(self, node, neighbor):
if not self.nodes[node.index]:
self.nodes[node.index] = node
if not self.nodes[neighbor.index]:
self.nodes[neighbor.index] = neighbor
self.nodes[node.index].createNeighbor(neighbor)
self.nodes[neighbor.index].createNeighbor(node)
def printNeighborsNeighbors(self, start_num):
node = self.nodes[start_num]
print(node.neighbors)
for n in node.neighbors:
print(n.neighbors)
def listNodes(self):
for node in self.nodes.values():
print(node)
有两个“坏”邻居(信息丢失),一个输入为{{1} }另一个输入为3
1 3
邻居在一个3 9
邻居之前输入但是在另一个{{1}之后输入邻居。good
时,bad
和bad
正确列出了他们的邻居,但printNeighborsNeighbors(4)
没有列出任何内容。所以这似乎是一个全有或全无的错误。你要么拥有所有真正的邻居,要么你根本没有邻居名单。这部分是最令人困惑的。这不是覆盖对象的问题,这更像是某种C ++风格的对象切片。 我总是可以通过图表字典轻松解决这个问题,但我想知道这里发生了什么。好像我误解了Python如何处理这些对象的重要事情。
感谢您对尝试的内容进行任何更正或建议。
按照MK的建议,这是一个有效的例子:input.txt中
9
我刚刚运行了这个.py所以它应该可以工作:
6
答案 0 :(得分:3)
问题在于您通过索引强制执行节点对象的唯一性。当调用neighborNodes()方法时,它会获得一个新创建的Node实例,只有在需要时才会添加到self.nodes(),这是"正确":它只会记录每个索引的一个Node实例。但是你仍然在创建一个新的Node实例,除非你首先将它传递给Node.createNeighbor()方法,并且该丢弃实例被记录为节点的邻居。结果,只记录了邻居关系的一个方向。
这是一个可能的解决方案:
if not self.nodes[node.index]:
self.nodes[node.index] = node
else:
node = self.nodes[node.index]
if not self.nodes[neighbor.index]:
self.nodes[neighbor.index] = neighbor
else:
neighbor = self.nodes[neighbor.index]
但我不喜欢它。实际上,您需要更改它以停止创建一次性实例,这对内存,性能,可读性和正确性都有好处。 你可以在Graph中添加一个名为getNode(n)的方法,如果它已经存在,它将返回一个节点对象,如果它还不存在,则创建一个新的(并注册)一个新的节点对象。然后你会使Node构造函数私有(可能没办法在Python中这样做),除了Graph之外没有其他人可以创建它们。