你如何通过python中的dijkstra算法运行三维列表?

时间:2017-12-01 09:00:06

标签: python list dijkstra path-finding

我是(试图)编写Dykstra算法的python实现的学生。我知道这个问题之前已被问过100次了,但我的情况有一些具体细节我还没有完全理解。

我有一个带有10个节点的加权非定向图。我的实际图表将有更多节点。该图表被排序为3维列表。我正在粘贴我们编写的程序的一些输出以生成图形。

`你好。我是(试图)编写Dykstra算法的python实现的学生。我知道这个问题之前已被问过100次了,但我的情况有一些具体细节我还没有完全理解。

我有一个带有10个节点的加权非定向图。我的实际图表将有更多节点。该图表被排序为3维列表。我正在粘贴我们编写的程序的一些输出以生成图形。

Node 1 : [[8, 3], [9, 11], [2, 12], [3, 12], [7, 6]]
Node 2 : [[5, 6], [4, 3], [1, 12], [8, 11], [7, 1]]
Node 3 : [[6, 2], [1, 12], [5, 7], [9, 1]]
Node 4 : [[2, 3], [8, 2], [10, 5], [5, 10], [7, 4]]
Node 5 : [[2, 6], [4, 10], [3, 7], [7, 8]]
Node 6 : [[3, 2], [9, 10]]
Node 7 : [[2, 1], [4, 4], [5, 8], [1, 6], [8, 3]]
Node 8 : [[1, 3], [2, 11], [4, 2], [7, 3], [10, 4]]
Node 9 : [[1, 11], [6, 10], [3, 1]]
Node 10 : [[4, 5], [8, 4]]

在可读性较差的格式中,图表存储为3维列表。因此,例如,在索引0处,存在到节点8,9,2,3和7的连接。节点8和0之间的权重是3.节点0和9之间的权重和11.我认为你得到了这个想法。

myGraph = [[[8,3],[9,11],[2,12],[3,12],[7,6]],[[5,6],[4,3] ,[1,12],[8,11],[7,1]],[[6,2],[1,12],[5,7],[9,1]],[[2, 3],[8,2],[10,5],[5,10],[7,4]],[[2,6],[4,10],[3,7],[7, 8]],[[3,2],[9,10]],[[2,1],[4,4],[5,8],[1,6],[8,3]], [[1,3],[2,11],[4,2],[7,3],[10,4]],[[1,11],[6,10],[3,1] ],[[4,5],[8,4]]]

所以挑战是找到一个dykstra的python实现,它将接受一个列表作为输入,并输出最佳路径。似乎大多数图表是围绕字典数据类型构建的,但这不是我的情况。

我已经开始尝试使用3D列表编写我自己的dijkstra版本,但没有运气,因为它对我来说有点复杂。我也尝试在Python中使用以前发布的dijkstra算法版本,但是它们被设计为运行字典而不是3维列表。这是我早些时候的尝试。

[[[4, 2], [2, 1], [3, 4]], [[1, 1], [4, 2], [3, 4]], [[1, 4], [2, 4], 
[4, 4]], [[1, 2], [2, 2], [3, 4]]]

class Graph:
  def __init__(self):
    self.nodes = set()
    self.edges = defaultdict(list)
    self.distances = {}

  def add_node(self, value):
    self.nodes.add(value)

  def add_edge(self, from_node, to_node, distance):
    self.edges[from_node].append(to_node)
    self.edges[to_node].append(from_node)
    self.distances[(from_node, to_node)] = distance


def dijsktra(graph, initial):
  visited = {initial: 0}
  path = {}

  nodes = set(graph.nodes)

  while nodes:
    min_node = None
    for node in nodes:
      if node in visited:
        if min_node is None:
          min_node = node
        elif visited[node] < visited[min_node]:
          min_node = node

    if min_node is None:
      break

    nodes.remove(min_node)
    current_weight = visited[min_node]

    for edge in graph.edges[min_node]:
      weight = current_weight + graph.distance[(min_node, edge)]
      if edge not in visited or weight < visited[edge]:
        visited[edge] = weight
        path[edge] = min_node

  return visited, path

我真的非常感谢任何人可以给予我的任何帮助,因为我一直在努力解决这个问题。谢谢!

2 个答案:

答案 0 :(得分:0)

尝试可用实现的建议似乎很好,但由于它不是一个复杂的算法,您可以尝试自己的代码。

Dijkstra的简单案例:

simple case of dijkstra

如图所示,您将分别在所有节点上运行算法。我们只考虑节点0,你应该有三个数据结构来选择路由&#39;和所有未被访问过的人&#39;并且在之前的迭代中未使用过&#39;。首先检查可以通过简单列表比较或检查实现的邻居,选择成本最低的邻居并将其添加到所选路由,并将未使用的邻居添加为上一次迭代中未使用的邻居。然后转到选定的路径节点,将其邻居与上一次迭代中的邻居进行比较。您将继续此操作,直到您选择的路径结构中的所有节点都可用。

答案 1 :(得分:0)

以下似乎适用于您的数据结构:

initial=1       #This is the number-label (not the index) of your starting node
assigned={}  #When a node has been given a permenant min-weight
visited={initial:0}  #When a node has a temporary min-weight
path={initial:[initial]}  #stores the path after a permenant weight has been assigned

myGraph = [[[8, 3], [9, 11], [2, 12], [3, 12], [7, 6]], [[5, 6], [4, 3], [1, 12], [8, 11], [7, 1]], [[6, 2], [1, 12], [5, 7], [9, 1]], [[2, 3], [8, 2], [10, 5], [5, 10], [7, 4]], [[2, 6], [4, 10], [3, 7], [7, 8]], [[3, 2], [9, 10]], [[2, 1], [4, 4], [5, 8], [1, 6], [8, 3]], [[1, 3], [2, 11], [4, 2], [7, 3], [10, 4]], [[1, 11], [6, 10], [3, 1]], [[4, 5], [8, 4]]]

while len(assigned)<len(myGraph):
    next_node= min(visited,key=visited.get)
    assigned[next_node]=visited[next_node]
    del visited[next_node]
    for node in myGraph[next_node-1]:  # The minus one is because your nodes are numbered from 1 (as apposed to 0).
        if node[0] in visited:
            if visited[node[0]]>assigned[next_node]+node[1]:
                visited[node[0]]=assigned[next_node]+node[1]
        else:
            if node[0] in assigned:
                if assigned[node[0]]+node[1]==assigned[next_node]:
                    path[next_node]=path[node[0]]+[next_node]
            else:
                visited[node[0]]=assigned[next_node]+node[1]

path是一个包含列表的dict,用于显示从初始节点开始的路径。我会解释每一步,但我想我只是解释Dikstra的算法(你似乎已经知道了) - 如果你有问题,请在评论中要求澄清。我希望这会对你有所帮助。