题目要求:计算节点之间最短路径的最大值、中位值和平均值;

其实解决这个问题的思路有很多,像什么单源最短路径…很多的算法可以解决这个问题。因为我这里在求最短路径的时候,将图简化成了无权值图,故而可以思考用更加简单的方式来解决这个问题,对于这个思路,我截了张PPT图,如下:

无权图广度优先遍历最短路径python 无权无向图最短路径_python


也就是在广度优先搜索的时候,我们存储以源节点开始的这颗逻辑树的所有的父子关系,然后根据这个父子关系,我们可以从子搜索父,从而找到从子到父的一条路径,如A->B。

现假设图中有10个节点,也就是我们要求无权图广度优先遍历最短路径python 无权无向图最短路径_无涯明月_02次两两节点之间的路径问题,然后比较相同源和目的节点路径的最小值,最后把这些最小值排序,找最大值、中位值和平均值。

完整的代码如下:

# 生成图的邻接矩阵,传入顶点集points和边集edges
# 传入节点列表points,节点有边关系列表edges
# return 该图的邻接矩阵存储
# 举例:
#    points = [0, 1, 2, 3, 4, 5]
#    edges = [(0,1), (1, 2), (2, 4), (3, 4), (3, 5)]
def generate_adjacency_matrix(points, edges):
    graph_data = [[0 for val in range(len(points))] for val in range(len(points))]
    for i, j in edges:
        graph_data[i][j] = graph_data[j][i] = 1
    return graph_data

# 初始化设置图的访问标识,默认都是没有访问过,即0,访问过需要置为1
# 传入节点列表points
# return 每个节点的访问标识列表
# 举例:
#    points = [0, 1, 2, 3, 4, 5]
def generate_matrix_flag(points):
    return [0 for val in range(len(points))]

# 从source_node节点开始建树,返回从源节点开始的父子关系列表
# 传入图的邻接矩阵adjacency_matrix、节点的标识矩阵matrix_flag,源节点source_node
# return 图中所有节点的父子关系列表child_relationship,如:节点1是节点2的爸爸 表示为:[1, 2]
# 举例:
#    adjacency_matrix = generate_adjacency_matrix
#    matrix_flag = generate_matrix_flag
#    source_node = 0
def get_all_father_relationship_from_graph(adjacency_matrix, matrix_flag, source_node):
    result = []
    que = [source_node]
    # 当前顶点置标识为1
    matrix_flag[source_node] = 1
    while len(que) != 0:
        # 找该元素直接连接的且没有访问过的节点
        current_node = que[0]
        que.remove(current_node)
        current_row = adjacency_matrix[current_node]  # 当前邻接矩阵行信息中记录了邻接节点(子节点)
        for j in range(len(current_row)):
            if matrix_flag[j] == 0 and current_row[j] != 0:
                # 添加进入队列中
                que.append(j)
                # 设置标识
                matrix_flag[j] = 1
                result.append([current_node, j])  # 存储该节点和其父节点信息
    return result

# 寻找从source_node到target_node节点的路径
# 传入源节点source_node,目标节点target_node,图中的所有父子关系列表child_relationship
# 返回 从源节点到目标节点的最短路径
# 举例:
#      source_node = 0
#      target_node = 16
#      child_relationship = get_all_father_relationship_from_graph
def find_path(source_node, target_node, child_relationship):
    # 由于chlid_relationship中存放的是父子关系列表,故而,应该从子找父
    resu = [target_node]
    while resu[0] != source_node:
        for i in child_relationship:
            if i[1] == target_node:
                target_node = i[0]
                resu.insert(0, target_node)
    return resu

# 比较,找源到目标的所有路径的最短路径
def compare_path(source_node, target_node, paths_list):
    paths = []
    for path in paths_list:
        if path[0] == source_node and path[len(path)-1]==target_node:
            paths.append(path)
    # 比较返回最短的那个路径
    min = paths[0]
    for i in range(len(paths)):
        ele = paths[i]
        if len(ele) < len(min):
            min = ele
    # 返回最短的那个路径
    return min

def sorted_paths(min_paths_list):
    # 基于比较每个最短路径的长度的冒泡排序
    for i in range(len(min_paths_list)):
        for j in range(len(min_paths_list)):
            if j > i:
                if len(min_paths_list[i]) > len(min_paths_list[j]):
                    temp = min_paths_list[j]
                    min_paths_list[j] = min_paths_list[i]
                    min_paths_list[i] = temp


# 这个函数只是调用,方便大家直接传入参数,然后得到结果,也就是说调用这个函数就可以了
# 传入顶点集、边集
def find_min_path_in_graph(points, edges):
    adjacency_matrix = generate_adjacency_matrix(points, edges)
    result_list = []
    for i in range(len(points)):
        for j in range(len(points)):
            if i!=j:
                # 由于我这里每次需要标志重置,故而设置为局部变量
                matrix_flag = generate_matrix_flag(points)
                result = find_path(i, j, get_all_father_relationship_from_graph(adjacency_matrix, matrix_flag, i))
                result_list.append(result)

    # 比较每个节点到另一个节点的最短路径
    min_paths_list = []
    for i in range(len(points)):
        for j in range(len(points)):
            if i != j :
                path = compare_path(i,j, result_list)
                min_paths_list.append(path)

    # 排序这些最短路径
    sorted_paths(min_paths_list)
    # print(min_paths_list) # 所有的最短路径

    # 获取图中所有最短路径的长度列表,方便找中位值,平均值,最大值
    len_list = []
    for path in min_paths_list:
        len_list.append(len(path)-1)

    # 返回各个值以及对应的路径
    return [
        [str(len_list[len(len_list) - 1]), str(min_paths_list[len(min_paths_list)-1])],
        [str(len_list[len(len_list) // 2]), str(min_paths_list[len(min_paths_list) // 2])],
        [str(sum(len_list) / len(len_list))]
    ]


# main函数
if __name__ == '__main__':
    # 定义点集和边集,其中边集举个例子,如接节点1和节点2有边就写作(1, 2)
    points = range(20)  # 点集合
    edges = [  # 边集和
        (10, 5), (10, 8), (8, 6), (10, 9), (10, 16), (2, 10),
        (1, 5), (6, 9), (9, 17), (0, 4), (3, 4), (12, 4), (12, 13),
        (12, 14), (14, 11), (17, 18), (9, 18), (9, 7), (18, 19),
        (11, 4), (11, 10), (15, 16),
    ]
    result = find_min_path_in_graph(points, edges)
    print("最短路径的最大值:" + result[0][0] + "。该值的其中一个路径是:" + result[0][1])
    print("最短路径的中位值:" + result[1][0] + "。该值的其中一个路径是:" + result[1][1])
    print("最短路径的平均值:" + result[2][0])

作者:无涯明月