【问题标题】:Python: Heapify a list of tuples (Dijkstra's Algo)Python:Heapify 一个元组列表(Dijkstra 的算法)
【发布时间】:2021-10-26 20:48:12
【问题描述】:

这是我的 Dijkstra 算法代码。 我已经声明了一个“顶点”类和一个“图形”类。 我正在使用 heapq 模块并堆积元组的列表“unvisitedQueue”。但即便如此,即使“v.getDistance()”返回 0 或 float('inf'),也会出现错误提示“TypeError: '

import heapq

class Vertex:
    def __init__(self, node):
        self.id = node
        self.adjacent = {}
        self.previous = None
        self.distance = float('inf')
    
    def addNeighbor(self, neighbor, weight = 0):
        self.adjacent[neighbor] = weight
    
    def getConnections(self):
        return self.adjacent.keys()
    
    def getVertex_ID(self):
        return self.id
    
    def getWeight(self, neighbor):
        return self.adjacent[neighbor]

    def setDistance(self, dist):
        self.distance = dist

    def getDistance(self):
        return self.distance

    def setPrevious(self, prev):
        self.previous = prev

    def __str__(self):
        return str(self.id) + "adjacent : " + str([x.id for x in self.adjacent])
    
class Graph:
    def __init__(self):
        self.vertDictionary = {}
        self.numVertices = 0
    
    def __iter__(self):
        return iter(self.vertDictionary.values())
    
    def addVertex(self, node):
        self.numVertices += 1
        newVertex = Vertex(node)
        self.vertDictionary[node] = newVertex
        return newVertex
    
    def getVertex(self, node):
        if node in self.vertDictionary:
            return self.vertDictionary[node]
        else:
            return None
    
    def addEdge(self, frm, to, cost = 0):
        if frm not in self.vertDictionary:
            self.addVertex(frm)
        if to not in self.vertDictionary:
            self.addVertex(to)
        self.vertDictionary[frm].addNeighbor(self.vertDictionary[to], cost)
        
        self.vertDictionary[to].addNeighbor(self.vertDictionary[frm], cost)
    
    def getVertices(self):
        return self.vertDictionary.keys()
    
    def setPrevious(self, current):
        self.previous = current
    
    def getPrevious(self):
        return self.previous
    
    def getEdges(self):
        edges = []
        for v in G:
            for w in v.getConnections():
                v_id = v.getVertex_ID()
                w_id = w.getVertex_ID()
                edges.append((v_id, w_id, v.getWeight(w)))
        return edges
def Dijkstra(G, s):
    source = G.getVertex(s)
    source.setDistance(0)
    visited = {}
    unvisitedQueue = [(v.getDistance(), v) for v in G]
    heapq.heapify(unvisitedQueue)
    while len(unvisitedQueue):
        uv = heapq.heappop(unvisitedQueue)
        currVert = uv[1]
        visited[currVert] = True
        for nbr in currVert.getConnections():
            if currVert.getDistance() + currVert.getWeight(nbr) < nbr.getDistance():
                nbr.setDistance(currVert.getDistance() + currVert.getWeight(nbr))
                print("Updated: Current = %s Neighbour = %s New Distance = %s" %(currVert.getVertex_ID(), nbr.getVertex_ID(), nbr.getDistance()))
            else:
                print("Not Updated: Current = %s Neighbour = %s Distance = %s" %(currVert.getVertex_ID(), nbr.getVertex_ID(), nbr.getDistance()))
        while len(unvisitedQueue):
            heapq.heappop(unvisitedQueue)
        unvisitedQueue = [(v.getDistance(), v) for v in G if v not in visited]
        heapq.heapify(unvisitedQueue)
    for v in G:
        print(source.getVertex_ID(), "to", v.getVertex_ID(), "-->", v.getDistance())

错误 -->

Traceback (most recent call last):
  File "d:\Python\Final 450\Graph\Dijkstra's_Algo.py", line 124, in <module>
    print(Dijkstra(G, "a"))
  File "d:\Python\Final 450\Graph\Dijkstra's_Algo.py", line 86, in Dijkstra 
    heapq.heapify(unvisitedQueue)
TypeError: '<' not supported between instances of 'Vertex' and 'Vertex'

【问题讨论】:

  • Vertex 声明在哪里?请分享。
  • "" TypeError: '
  • 当比较一个元组时,如果第一个值相等,那么它会尝试使用第二个值进行比较,在你的情况下是一个顶点。在您的堆中,您应该存储一个元组,该元组的第二个参数可能具有唯一编号,例如索引,因为当距离相同时,您可以获得任何顶点。
  • Please do not upload images of code/errors when asking a question. 您包含的图像并没有告诉我们您的文本摘要没有告诉我们的任何内容。它也是isn't complete。您应该复制并粘贴整个回溯,将其粘贴进去,并将其格式化为代码。

标签: python list tuples heap dijkstra


【解决方案1】:

发生错误是因为元组是按字典顺序比较的。如果两个距离相同,则比较会转到 Vertex 对象本身。

很容易想到两种解决方案。第一种是简单地在Vertex 之前但在距离之后向元组添加一个唯一索引。这很简单,即使您无法访问 Vertex 类也可以使用:

unvisitedQueue = [(v.getDistance(), i, v) for i, v in enumerate(G) if v not in visited]

第二个选项是将Vertex修改为__lt__魔术方法:

def __lt__(self, other):
    return self.getDistance() < other.getDistance()

这很好,因为您现在可以更直接地堆化:

unvisitedQueue = [v for v in G if v not in visited]

【讨论】:

  • @don'ttalkjustcode 应该是 O(N log N) 与 O(N) 的比较。你不会注意到差异
  • 您所节省的只是额外的函数调用。比较本身更便宜,并且可以通过任何方式完成。现在是对 getDistance 的 N log N 次调用,而不是对 getDistance 的 N 次调用,然后是对 tuple.__lt__ 的 N log N 次调用。这一晚居然加快了速度。过早的优化和所有...
  • @don'ttalkjustcode。我的意思是创建密钥需要 O(N) 次调用 getDistance,而 heapifying 直接需要 O(N log N) 次调用。
  • 做到了,我也明白了。谢谢,伙计。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-08-29
  • 2015-06-06
  • 1970-01-01
  • 2013-12-23
  • 1970-01-01
相关资源
最近更新 更多