为什么我的bfs实现效率低下?

时间:2017-07-15 07:32:10

标签: python optimization graph-theory breadth-first-search zelle-graphics

我最近开始尝试编写一个使用Zelle的python编程书中的graphics.py模块的程序。程序的想法是它创建一个图形窗口并接受两个点,即开始和结束。它绘制起点并进行bfs搜索,然后一旦到达终点,它就会绘制最短路径(无论如何还没有对角线)。它在技术上有效,但它非常慢,并且在前两到三次迭代中的任何地方都需要永远。我试着到处寻找具有快速查找的数据结构,以及实现节点以便允许回溯的有效方法,而我无法弄明白。我非常感谢任何帮助,向我解释我可以改进我的实施。

以下是python 3.5.2中的代码:

from graphics import *
from collections import deque
TITLE = "Breadth-First Search"
WIDTH = 500
HEIGHT = 500


win = GraphWin(TITLE, WIDTH, HEIGHT)
win.setCoords(0,0,20,20)

class Node:
    def __init__(self, x, y, parent = None):
        self.x = x
        self.y = y
        self.parent = parent
        self.pos2D = Point(self.x, self.y)
        self.pos2D.draw(win)

    def getPos(self):
        return (self.x, self.y)

    def draw(self, win, color = None):
        if color != None:
            self.pos2D.undraw()
            self.pos2D.setFill(color)
            self.pos2D.draw(win)
            return
        self.pos2D.draw(win)


def neighbors(state):
    return (Node(state.x, state.y+1, state), Node(state.x, state.y-1, 
state), Node(state.x-1, state.y, state), Node(state.x+1, state.y, 
state))

def drawPath(endState):
    state.draw(win, 'red')
    while state.parent != None:
        state = state.parent
        state.draw(win, 'red')

def bfs():
    start = (10,10)
    finish = (15,15)

    explored = set()

    frontier = deque()
    frontier.append((Node(start[0], start[1])))

    while len(frontier) != 0:
        state = frontier.popleft()
        explored.add(state)

        if state.getPos() == finish:
            break

        for neighbor in neighbors(state):
            if neighbor not in explored:
                frontier.append(neighbor) 
bfs()

1 个答案:

答案 0 :(得分:1)

运行代码的主要延迟是此优化:

if neighbor not in explored:
    frontier.append(neighbor)

因为它根本不起作用。在此处添加else:子句以将单词skipped打印到控制台,您将看到永远不会使用else:。优化不起作用,因为您放入集合中的内容都是唯一的。 @ user2357112关于缺少__hash____eq____ne__方法的评论是解决此问题的正确方法(我在下面使用了更简单的修复方法。)

次要延迟是您正在创建(和绘制)许多Node个实例,而这些实例最终未被使用,因为它们已被探索过。

下面是代码的返工,试图解决这两个问题:

from collections import deque
from graphics import *

TITLE = "Breadth-First Search"

WIDTH, HEIGHT = 500, 500

class Node:
    def __init__(self, x, y, parent=None):
        self.x = x
        self.y = y
        self.parent = parent
        self.pos2D = Point(self.x, self.y)
        self.pos2D.draw(win)

    def getPos(self):
        return (self.x, self.y)

def unexplored_neighbors(state):
    neighbors = []

    for dx, dy in [(0, 1), (0, -1), (-1, 0), (1, 0)]:
        if (state.x + dx, state.y + dy) not in explored:
            neighbors.append(Node(state.x + dx, state.y + dy, state))

    return neighbors

def bfs():
    start = (10, 10)
    finish = (15, 15)

    frontier = deque()
    frontier.append(Node(*start))

    while frontier:
        state = frontier.popleft()

        if state.getPos() == finish:
            break

        explored.add((state.x, state.y))

        for neighbor in unexplored_neighbors(state):
            frontier.append(neighbor)

win = GraphWin(TITLE, WIDTH, HEIGHT)
win.setCoords(0, 0, 20, 20)

explored = set()

bfs()

win.getMouse()
win.close()

可以帮助您找到性能问题的是cProfile模块:

# bfs()
import cProfile
cProfile.run('bfs()')

# win.getMouse()
# win.close()

您可以在The Python Profilers

中阅读

enter image description here