最短路径算法

时间:2021-05-13 15:50:28

标签: python graph

我正在尝试计算未加权图上两个顶点之间的最短路径。我的图表来自 csv 文件,我将所有信息放在字典结构中: 编辑:

类图:

def __init__(self, directed=False):
    self._directed = directed
    self._number = 0            
    self._vertices = {}    

def insert_vertex(self, x):
    v = Vertex(x)
    self._vertices[v] = {}      
    self._number = len(self._vertices)
    return v

def insert_edge(self, u, v, x=None):
    e = Edge(u, v, x)
    self._vertices[u][v] = e  
    self._vertices[v][u] = e  

def incident_edges(self, v, outgoing=True):
    for edge in self._vertices[v].values(): 
        if not self._directed:
                yield edge
        else:  
            x, y = edge.endpoints()
            if (outgoing and x == v) or (not outgoing and y == v):
                yield edge

def is_directed(self):
    return self._directed  

def vertex_count(self):
    return self._number

def vertices(self):
    return self._vertices.keys()

def edge_count(self):
    total = sum(len(self._vertices[v]) for v in self._vertices)
    return total if self._directed else total // 2


def edges(self):
    result = set()     
    for secondary_map in self._vertices.values():
        result.update(secondary_map.values())  
    return result


def get_edge(self, u, v):
    edge = self._vertices[u].get(v) 
    if edge != None and self._directed: 
        _, x = edge.endpoints           
        if x != v:
            edge = None
    return edge


def degree(self, v, outgoing=True):
    adj = self._vertices
    if not self._directed:
        count = len(adj[v])
    else:
        count = 0
        for edge in adj[v].values():
            x, y = edge.endpoints()
            if (outgoing and x == v) or (not outgoing and y == v):
                count += 1
    return count


def remove_edge(self, u, v):
    if  u in self._vertices.keys() and v in self._vertices[u].keys():
        del self._vertices[u][v]
        del self._vertices[v][u]

def remove_vertex(self, v):
    if v in self._vertices.keys():
        lst = [i for i in self.incident_edges(v)]
        for i in lst:
            x, y = i.endpoints()
            self.remove_edge(x,y)
        del self._vertices[v]
    #return v

def github_csv():
    lista = []
    with open('Github1.csv', 'r') as csv_file:
        data = csv.DictReader(csv_file)
        next(data)
        for row in data:
            lista.append(row)
        rel_dict = {}
        for d in lista:
            if d["follower"] in rel_dict.keys():
                rel_dict[d['follower']].append(d['followed'])
            else:
                rel_dict[d['follower']] = [d['followed']]
        return rel_dict

git_hub() 的输出是:

{'9236': ['1570', '13256', '45703', '10005', '30355', '1564', '11917'], '13256': ['9236', '1570', '1563', '22390', '4140', '28106', '11914', '10005', '1567', '1565', '28464', '14922', '41223', '1564', '14613', '1569', '1934', '32872', '11917', '109144', '144589']}

def build_graph():
    graph = Graph(True)
    git = github_csv()
    for k,v in git.items():
        k_vertex = graph.insert_vertex(k)
        for v_item in v:
            v_item_vertex = graph.insert_vertex(v_item)
            graph.insert_edge(k_vertex,v_item_vertex)
    graph.printG()
    return graph

输出类似于:

vertex  59216  grau_in:  1 grau_out:  1
  (4140, 59216) 
vertex  59570  grau_in:  1 grau_out:  1
  (4140, 59570) 

我正在使用以下内容来计算两个顶点之间的最短路径:

def shortest_path(graph, start, goal):
    explored = []

    queue = [[start]]

    if start == goal:
        print("Same Node")
        return

    while queue:
        path = queue.pop(0)
        node = path[-1]

        if node not in explored:
            neighbours = graph[node]

            for neighbour in neighbours:
                new_path = list(path)
                new_path.append(neighbour)
                queue.append(new_path)

                if neighbour == goal:
                    print("Shortest path = ", *new_path)
                    return
            explored.append(node)

    print("So sorry, but a connecting" \
          "path doesn't exist :(")
    return

输出为:

 Traceback (most recent call last):
  File "<input>", line 1, in <module>
  File "C:\Program Files\JetBrains\PyCharm Community Edition 2020.2.3\plugins\python-ce\helpers\pydev\_pydev_bundle\pydev_umd.py", line 197, in runfile
    pydev_imports.execfile(filename, global_vars, local_vars)  # execute the script
  File "C:\Program Files\JetBrains\PyCharm Community Edition 2020.2.3\plugins\python-ce\helpers\pydev\_pydev_imps\_pydev_execfile.py", line 18, in execfile
    exec(compile(contents+"\n", file, 'exec'), glob, loc)
  File "C:/Users/sandr/PycharmProjects/ProjetoEDA/main.py", line 334, in <module>
    shortest_path(graph,'1563','133')
  File "C:/Users/sandr/PycharmProjects/ProjetoEDA/main.py", line 271, in shortest_path
    neighbours = graph[node]
TypeError: 'Graph' object is not subscriptable

有人可以帮助我理解我做错了什么吗?

2 个答案:

答案 0 :(得分:0)

Class 本身不支持 [] 操作符,这意味着如果你定义了一个类 Foo 你不能这样做

foo = Foo()
a = foo[1] # throw subscriptable error

如果你想能够做graph[node],你需要定义getitem方法。有关 postthis post

的更多信息

在你的代码中,你把图形作为图形的一个属性,所以如果你没问题,你可以使用graph._vertices[node]。您的图在您的 Graph 类中表示为 {Vertex: {Vertex: Edge}},因此节点必须是 Vertex 类的实例并返回一个看起来像 {Vertex: Edge} 的字典。

为了不迷失在自己的代码中,我建议您使用类型提示,然后您就会确切地知道自己在做什么。我知道这有点复杂,因为您必须安装 Visual Studio 代码和 pyright,但您肯定会更有效率,因为您将准确了解所用对象的类型。这将使调试更加容易。

答案 1 :(得分:0)

从您的代码的一般流程来看,我认为您希望 graph[node] 神奇地返回一系列相邻节点。同样,您需要了解您已实现(或选择)的接口。 Graph 中没有这样的设施。相反,您需要遍历 incident_edges,处理每个此类边的目标节点。

for neighbour_edge in graph.incident_edges(node):
    # access the edge endpoint that is *not* "node"
    neighbour = neighbour_edge.???    # Again, your posting is incomplete.  You'll have to do this part.