Python 这种广度优先的搜索能更快吗?
我有一个数据集,它是一个大的未加权循环图,循环发生在大约5-6条路径的循环中。它由大约8000个节点组成,每个节点有1-6个连接,通常约4-5个连接。我正在进行单对最短路径计算,并实现了以下代码来进行广度优先搜索Python 这种广度优先的搜索能更快吗?,python,algorithm,computer-science,breadth-first-search,Python,Algorithm,Computer Science,Breadth First Search,我有一个数据集,它是一个大的未加权循环图,循环发生在大约5-6条路径的循环中。它由大约8000个节点组成,每个节点有1-6个连接,通常约4-5个连接。我正在进行单对最短路径计算,并实现了以下代码来进行广度优先搜索 from Queue import Queue q = Queue() parent = {} fromNode = 'E1123' toNode = 'A3455' # path finding q.put(fromNode) parent[fromNode] = 'Root'
from Queue import Queue
q = Queue()
parent = {}
fromNode = 'E1123'
toNode = 'A3455'
# path finding
q.put(fromNode)
parent[fromNode] = 'Root'
while not q.empty():
# get the next node and add its neighbours to queue
current = q.get()
for i in getNeighbours(current):
# note parent and only continue if not already visited
if i[0] not in parent:
parent[i[0]] = current
q.put(i[0])
# check if destination
if current == toNode:
print 'arrived at', toNode
break
上面的代码使用Python2.6队列模块,GetNeights只是一个子例程,它进行一个MySQL调用,并以元组列表的形式返回邻居,例如“foo”、“bar”,。SQL调用很快
代码运行正常,但是测试到大约7层的深度大约需要20秒才能运行2.5GHz Intel 4GB RAM OS X 10.6
我欢迎大家对如何改进这段代码的运行时间提出意见。我敢打赌这台机器有多个内核,不是吗?并行运行
嗯,BFS不包括标记你已经看到的节点,这样你就不会再访问它们了吗?好吧,考虑到评论的投票结果,我现在就回答这个问题 紧循环中的SQL肯定会减慢您的速度。我不管电话有多快。想想看——你要求解析一个查询,运行一个查找——尽管如此,它仍然处于一个紧密的循环中。您的数据集看起来像什么?您可以将整个数据集选择到内存中,或者至少在MySQL之外使用它吗 如果您在内存中处理这些数据,您将看到显著的性能提升。类似这样的内容:
#!/usr/bin/env python
from Queue import Queue
def traverse_path(fromNode, toNode, nodes):
def getNeighbours(current, nodes):
return nodes[current] if current in nodes else []
def make_path(toNode, graph):
result = []
while 'Root' != toNode:
result.append(toNode)
toNode = graph[toNode]
result.reverse()
return result
q = Queue()
q.put(fromNode)
graph = {fromNode: 'Root'}
while not q.empty():
# get the next node and add its neighbours to queue
current = q.get()
for neighbor in getNeighbours(current, nodes):
# use neighbor only continue if not already visited
if neighbor not in graph:
graph[neighbor] = current
q.put(neighbor)
# check if destination
if current == toNode:
return make_path(toNode, graph)
return []
if __name__ == '__main__':
nodes = {
'E1123': ['D111', 'D222', 'D333', 'D444'],
'D111': ['C01', 'C02', 'C04'],
'D222': ['C11', 'C03', 'C05'],
'D333': ['C01'],
'C02': ['B1'],
'B1': ['A3455']
}
result = traverse_path('E1123', 'A3455', nodes)
print result
['E1123', 'D111', 'C02', 'B1', 'A3455']
如果将SQL查询替换为列表字典,这将是一个棘手的部分,您将获得此性能。我认为您的意思是Python多处理。第二,8000个节点将很容易放入内存中。很好的调用!包含节点信息的表只是fromNode、toNode的行。我将研究如何简单地将其加载到内存中。可能只是一个大的字典结构。作为一个简单的测试,我在CREATE表定义中使用ENGINE=memory将MySQL加载到内存中。同样的代码现在大约在2.5秒内完成!派对有点晚了,但你是在用事先准备好的陈述来提问吗?应该能够节省一些SQL处理时间,特别是在内存中的变体中。确实如此。如果节点已经被放置在父节点[]中,那么它以前已经被看到过,因此它不会被放入队列中再次执行操作。哦,我明白了。对不起,我错过了。不过,将该标志放入每个节点比操纵不断增长的集合要便宜。太棒了,休。我在内存表中的性能一直很好。我将尝试下一步。有大约14K的连接,这将最终成为一个web应用程序,因此我需要仔细考虑加载到内存中的工作方式。我发现我的代码与你的相似,休,但是你的肯定更优雅。除了“neighbor/neighbor”的区域设置相关拼写外,我对上述内容的唯一额外建议是在make_path中调用result.reverse,因为它按从node->toNode的顺序返回列表