简体   繁体   English

python dijkstra的算法使用类实现的可能问题

[英]Possible problem with python dijkstra's algorithm implementation using classes

So I have been trying to create a graph program in python with classes that has dfs, bfs and dijkstra's algorithmn implemented within it and so far have come up with:所以我一直试图在 python 中创建一个图形程序,其中包含在其中实现的 dfs、bfs 和 dijkstra 算法的类,到目前为止已经提出:

class Vertex:
    def __init__(self, name):
        self.name = name
        self.connections = {}

    def addNeighbour(self, neighbour, cost):
        self.connections[neighbour] = cost


class Graph:
    def __init__(self):
        self.vertexs = {}

    def addVertex(self, newVertex):
        new = Vertex(newVertex)
        self.vertexs[newVertex] = new

    def addEdge(self, src, dest, cost):
        self.vertexs[src].addNeighbour(self.vertexs[dest], cost)

    def dfs(self, start, end, visited):
        visited[start] = True
        print(start, end=' ')
        if start == end:
            # End node found
            return True
        else:
            # Use depth first search
            for connection in graph.vertexs[start].connections:
                if visited[connection.name] == False:
                    if self.dfs(connection.name, end, visited) == True:
                        # Return true to stop extra nodes from being searched
                        return True

    def bfs(self, start, end, visited, queue):
        if len(queue) == 0:
            # Queue is empty
            queue.append(start)
        visited[start] = True
        currentNode = queue.pop(0)
        print(currentNode, end=' ')
        if start == end:
            # End node found
            return True
        else:
            # Do breadth first search
            for connection in graph.vertexs[currentNode].connections:
                if visited[connection.name] == False:
                    # Queue all its unvisited neighbours
                    queue.append(connection.name)
            for newNode in queue:
                self.bfs(newNode, end, visited, queue)

    def dijkstra(self, current, currentDistance, distances, visited, unvisited):
        for neighbour, distance in distances.items():
            if neighbour.name not in unvisited:
                continue
            newDistance = currentDistance + distance
            if unvisited[neighbour.name] is None or unvisited[neighbour.name] > newDistance:
                unvisited[neighbour.name] = newDistance
        visited[current] = currentDistance
        del unvisited[current]
        if not unvisited:
            return True
        candidates = [node for node in unvisited.items() if node[1]]
        current, currentDistance = sorted(candidates)[0]
        self.dijkstra(current, currentDistance, graph.vertexs[current].connections, visited, unvisited)
        return visited


def setup():
    graphList = {
        # Node number: [destination number, cost]
        0: {4: 6, 6: 1},
        1: {6: 2},
        2: {0: 9, 1: 4, 3: 3},
        3: {4: 7},
        4: {1: 3, 5: 5},
        5: {0: 2, 1: 6, 4: 3},
        6: {2: 4, 3: 6}
    }
    graph = Graph()

    for i in range(len(graphList)):
        graph.addVertex(i)

    for dictLength in range(len(graphList)):
        for key in list(graphList[dictLength].keys()):
            graph.addEdge(dictLength, key, graphList[dictLength][key])
    return graph, graphList


graph, graphList = setup()


print("DFS travsersal path from node 1 to node 0:")
graph.dfs(1, 0, [False] * len(graphList))
print()

print("BFS traversal path from node 1 to node 0:")
graph.bfs(1, 0, [False] * len(graphList), [])
print()

print("Shortest possible path from node 1 to 0:")
result = graph.dijkstra(1, 0, graph.vertexs[2].connections, {}, {node: None for node in graphList})
cost = result[len(result) - 1]
path = " ".join([str(arrInt) for arrInt in list(result.keys())])
print(path, "costing", cost)

But there seems to be a problem with the output I think.但是我认为输出似乎有问题。 If I wanted to travel from node 1 to node 0, the current output is:如果我想从节点 1 到节点 0,当前输出是:

DFS travsersal path from node 1 to node 0: 1 6 2 0 BFS traversal path from node 1 to node 0: 1 6 2 3 0 3 4 5 Shortest possible path from node 1 to 0: 1 0 3 4 5 6 2 costing 10从节点1到节点0的DFS遍历路径:1 6 2 0 从节点1到节点0的BFS遍历路径:1 6 2 3 0 3 4 5 从节点1到0的最短路径: 1 0 3 4 5 6 2 costing 10

However, I think the output should be:但是,我认为输出应该是:

DFS travsersal path from node 1 to node 0: 1 6 2 0 4 5 3 BFS traversal path from node 1 to node 0: 1 6 2 3 0 4 5 Shortest possible path from node 1 to 0: 1 6 2 0 costing 15从节点1到节点0的DFS遍历路径:1 6 2 0 4 5 3 从节点1到节点0的BFS遍历路径:1 6 2 3 0 4 5 从节点1到0的最短路径:1 6 2 0 costing 15

Can anyone see any problems with this?任何人都可以看到这有什么问题吗?

Thanks!谢谢!

There are actually several issues in your code:您的代码中实际上有几个问题:

  1. You need to specify to your Djikstra's algorithm where to stop, in your code it is not mentioned what is the end node (in your example it should be 0)您需要向 Djikstra 算法指定停止的位置,在您的代码中没有提到什么是结束节点(在您的示例中它应该是 0)

  2. Computing the cost as cost = result[len(result) - 1] does not get you the last element in a dictionary (dictionaries are usually not ordered, so the "last element" does not even exist!).计算成本为cost = result[len(result) - 1]不会得到字典中的最后一个元素(字典通常没有排序,所以“最后一个元素”甚至不存在!)。 You should retrieve the cost as cost = result[end] , where end is the final node, 0 in your example.您应该检索成本为cost = result[end] ,其中end是最终节点,在您的示例中为 0 。

  3. You are calling the function as result = graph.dijkstra(1, 0, graph.vertexs[2].connections, {}, {node: None for node in graphList}) , however, the third argument of this function should be the set of neighbours of the initial node, so it should be graph.vertexs[1].connections in your case.您将函数调用为result = graph.dijkstra(1, 0, graph.vertexs[2].connections, {}, {node: None for node in graphList}) ,但是,此函数的第三个参数应该是初始节点的一组邻居,因此在您的情况下应该是graph.vertexs[1].connections

In summary, to make the code work as expected, you can modify the function as follows:综上所述,为了使代码按预期工作,您可以对函数进行如下修改:

def dijkstra(self, current, currentDistance, distances, visited, unvisited, end):
    for neighbour, distance in distances.items():
        if neighbour.name not in unvisited:
            continue
        newDistance = currentDistance + distance
        if unvisited[neighbour.name] is None or unvisited[neighbour.name] > newDistance:
            unvisited[neighbour.name] = newDistance
    visited[current] = currentDistance

    if current == end:
      return visited

    del unvisited[current]
    if not unvisited:
        return True
    candidates = [node for node in unvisited.items() if node[1]]
    current, currentDistance = sorted(candidates)[0]
    
    self.dijkstra(current, currentDistance, graph.vertexs[current].connections, visited, unvisited, end)
    return visited

And call it as follows:并按如下方式调用它:

print("Shortest possible path from node 1 to 0:")
start = 1
end = 0
result = graph.dijkstra(start, 0, graph.vertexs[start].connections, {}, {node: None for node in graphList}, end)
cost = result[end]
path = " ".join([str(arrInt) for arrInt in list(result.keys())])
print(path, "costing", cost)

By doing this, the output becomes通过这样做,输出变成

Shortest possible path from node 1 to 0: 1 6 2 0 costing 15从节点 1 到 0 的最短路径: 1 6 2 0 costing 15

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM