使用邻接表计算节点之间的步骤

时间:2019-02-13 13:28:49

标签: python graph networkx

adj_list={1:[2,4],2:[1,3,4,8],3:[2,6,8,7],4:[1,5,2],5:[4,6],6:[3,9,5],7:[3,8,9,10],8:[2,3,7],9:[6,7,10],10:[7,9]}
def func(x,y):
t=0
xx=x
global i
for i in range(len(adj_list[xx])):
    if y in adj_list[xx]:
        t=t+1
        # print(x,y,t)
        break
    else:
        if xx<y:
            t = t + 1
            xx = xx + 1
    i=0
print(x,y,t)

func(1,6)

我除了输出类似:

func(1,10) :1-2-3-7-10(4) or 1-2-8-7-10(4) 

4不应是1到10的步长

3 个答案:

答案 0 :(得分:2)

如果您想在纯Python中快速轻松地实现,则可以使用递归遍历相邻列表并计算从每个节点到达目的地所需的步骤数,然后仅记录花费最少路径的路径步骤。

def count_steps(current_vertex, destination, steps=0, calling=0):
    """
    Counts the number of steps between two nodes in an adjacent array
    :param current_vertex: Vertex to start looking from
    :param destination: Node we want to count the steps to
    :param steps: Number of steps taken so far (only used from this method, ignore when calling)
    :param calling: The node that called this function (only used from this method, ignore when calling)
    :return: 
    """
    # Start at illegal value so we know it can be changed
    min_steps = -1
    # Check every vertex at the current index
    for vertex in adj_list[current_vertex]:
        if destination in adj_list[current_vertex]:
            # We found the destination in the current array of vertexes
            return steps + 1
        elif vertex > calling:
            # Make sure the vertex we will go to is greater than wherever we want to go so we don't end up in a loop
            counted = count_steps(vertex, destination, steps + 1, current_vertex)
            if counted != -1 and (min_steps == -1 or counted < min_steps):
                # If this is actually the least amount of steps we have found
                min_steps = counted
    return min_steps

请注意,当我们在当前顶点的数组中找到目标时,将添加一个。这是因为要实际到达我们找到的节点,还需要再走一步。

答案 1 :(得分:1)

如果您正在寻找从特定节点到任何其他节点的最少步骤,我建议使用Dijkstra's Algorithm。这不是一个可以在单个循环中解决的问题,它需要考虑到最短步骤数的值队列。

答案 2 :(得分:1)

您可以为此使用networkx。首先使用keys作为节点并使用edges作为值来构建网络。但是,考虑到边缘必须是包含({source_node, dest_node)的元组列表,因此边缘需要做一些额外的工作。

解决这个问题的一种方法是从字典中的所有条目中获取所有键值组合。

对于节点,您只需要:

nodes = list(adj_list.keys())

现在让我们从字典中获取边列表。为此,您可以使用以下列表理解:

edges = [(k,val) for k, vals in adj_list.items() for val in vals]
# [(1, 2), (1, 4), (2, 1), (2, 3), (2, 4)...

因此,此列表将字典中的条目包含为元组的简单列表:

1: [2, 4]         ->    (1, 2), (1, 4)
2: [1, 3, 4, 8]   ->    (2, 1), (2, 3), (2, 4), (2, 8)
...

现在,让我们使用相应的节点和边来构建网络:

import networkx as nx
G=nx.Graph()
G.add_edges_from(edges)
G.add_nodes_from(nodes)

已经建立了网络,为了找到不同节点之间的步骤,可以使用shortest_path,它将为您提供两个给定节点之间的最短路径。因此,如果您想找到节点110之间的最短路径:

nx.shortest_path(G, 1,10)
# [1, 2, 3, 7, 10]

如果您对长度感兴趣,只需选择列表的len。让我们来看另一个示例:

nx.shortest_path(G, 1,6)
# [1, 2, 3, 6]

这可以通过直接绘制网络来更容易地检查:

nx.draw(G, with_labels = True)
plt.show()

enter image description here


在节点110之间最短的情况下,中间节点为[1, 2, 3, 7, 10]

enter image description here