关闭

Python广度优先搜索得到两点间最短路径

标签: python算法
655人阅读 评论(4) 收藏 举报
分类:

前言

之前一直写不出来,这周周日花了一下午终于弄懂了= =|| , 顺便放博客里,方便以后忘记了再看看
要实现的是输入一张 图,起点,终点,输出起点和终点之间的最短路径

广度优先搜索

适用范围: 无权重的图,与深度优先搜索相比,深度优先搜索法占内存少但速度较慢,广度优先搜索算法占内存多但速度较快

复杂度: 时间复杂度为O(V+E),V为顶点数,E为边数

思路

广度优先搜索是以层为顺序,将某一层上的所有节点都搜索到了之后才向下一层搜索;
比如下图:
这里写图片描述

从0结点开始搜索的话,一开始是0、将0加入队列中;
然后下一层,0可以到达的有1,2,4,将他们加入队列中;
接下来是1,1能到达的且未被访问的是结点3
顺序就是 01,2,43,这里用下划线表示每一层搜索得到的结点;

每一次用cur = que[head]取出头指针指向的结点,并搜索它能到达的结点;因此,可以用一个队列que来保存已经访问过的结点,队列有头指针head以及尾指针tail,起点start与结点i有边并且结点i未被访问过,则将该结点加入队列中,tail指针往后移动;当tail等于顶点数时算法结束
对于每一次while循环,head都加一,也就是往右边移动,比如一开始head位置是0,下一层的时候head位置元素就为1,也就是搜索与结点1有边的且未被访问的结点
用一个数组book来标识结点i是否已经被访问过;用字典来保存起点到各个点的最短路径;
代码如下:

import numpy as np

ini_matrix = [
          [0, 1, 1, 0, 1],
          [1, 0, 0, 1, 0],
          [1, 0, 0, 0, 1],
          [0, 1, 0, 0, 0],
          [1, 0, 1, 0, 0]
         ]


def bfs(matrix_para, start_point_para, end_point_para):
    """
    广度优先搜索
    :param matrix_para 图
    :param start_point_para 起点
    :param end_point_para 终点
    :return: 返回关联度
    """
    matrix = matrix_para
    start_point = start_point_para
    end_point = end_point_para

    vertex_num = len(matrix) # 顶点个数

    que = np.zeros(vertex_num, dtype=np.int) # 队列, 用于存储遍历过的顶点
    book = np.zeros(vertex_num, dtype=np.int) # 标记顶点i是否已经被访问,1表被访问,0表未被访问

    point_step_dict = dict() # key:点,value:起点到该点的步长

    # 队列初始化
    head = 0
    tail = 0

    # 从起点出发,将起点加入队列
    que[tail] = start_point # 等号右边为顶点号(起点)
    tail += 1
    book[start_point] = 1 # book[i] i为顶点号

    while head<tail:
        cur = que[head]
        for i in range(vertex_num):
            # 判断从顶点cur到顶点i是否有边,并判断顶点i是否已经被访问过
            if matrix[cur][i] == 1 and book[i] == 0:
                que[tail] = i # 将顶点i放入队列中
                tail += 1 # tail指针往后移
                book[i] = 1 # 标记顶点i为已经访问过
                point_step_dict[i] = head + 1 # 记录步长
            if tail == vertex_num: # 说明所有顶点都被访问过
                break
        head += 1

    for i in range(tail):
        print(que[i])

    try:
        relevancy = point_step_dict[end_point]
        return relevancy
    except KeyError: # 捕获错误,如果起点不能到达end_point,则字典里没有这个键,返回None
        return None

result = bfs(ini_matrix, 1, 4)
print("result:", result)

错误

在经同学的一番调教之后,我深刻意识到了这段代码有个问题(不能用head记录步长),就是对于有环的时候,可能得到的步长(迭代次数)会比最短路径还大;
比如,起点为4,终点为3:这里每一遍迭代都是一次while循环
第一遍迭代,队列4,head指向4,步长为0
第二遍迭代,队列4,0 , 2,head指向0, 步长为1
第三遍迭代,队列4,0 , 2,1,head指向2,步长为2,
第四遍迭代,对于2,2周围都被访问过了,但此时head仍然+=1为3,这就导致了下一次的步长会比实际的步长多1
第五遍迭代, 3,步长为4

纠正

改进的思路:用count记录步长,flag用于标识当前搜索能到达的边的该结点cur = que[head]周围是否已经被访问过,False表示没有,True表示该结点i周围都被访问过了;也就是,当flag为False时,表示对于cur周围已经都访问过了,此时步长count不需要自增1;

import numpy as np

ini_matrix = [
          [0, 1, 1, 0, 1],
          [1, 0, 0, 1, 0],
          [1, 0, 0, 0, 1],
          [0, 1, 0, 0, 0],
          [1, 0, 1, 0, 0]
         ]


def bfs(matrix_para, start_point_para, end_point_para):
    """
    广度优先搜索
    :param matrix_para 图
    :param start_point_para 起点
    :param end_point_para 终点
    :return: 返回关联度
    """
    matrix = matrix_para
    start_point = start_point_para
    end_point = end_point_para

    vertex_num = len(matrix) # 顶点个数

    que = np.zeros(vertex_num, dtype=np.int) # 队列, 用于存储遍历过的顶点
    book = np.zeros(vertex_num, dtype=np.int) # 标记顶点i是否已经被访问,1表被访问,0表未被访问

    point_step_dict = dict() # key:点,value:起点到该点的步长

    # 队列初始化
    head = 0
    tail = 0

    # 迭代次数
    count = 0

    # 从0号顶点出发,将0号顶点加入队列
    que[tail] = start_point # 等号右边为顶点号(起点)
    tail += 1
    book[start_point] = 1 # book[i] i为顶点号

    while head<tail:
        flag = False # 用flag标识结点i是否周围都是被访问过的
        cur = que[head]
        for i in range(vertex_num):
            # 判断从顶点cur到顶点i是否有边,并判断顶点i是否已经被访问过
            if matrix[cur][i] == 1 and book[i] == 0:
                que[tail] = i # 将顶点i放入队列中
                tail += 1 # tail指针往后移
                book[i] = 1 # 标记顶点i为已经访问过
                point_step_dict[i] = count + 1 # 记录步长
                flag = True
            if tail == vertex_num: # 说明所有顶点都被访问过
                break
        if flag:
            count += 1
        head += 1

    for i in range(tail):
        print(que[i])

    try:
        relevancy = point_step_dict[end_point]
        return relevancy
    except KeyError:
        return None

result = bfs(ini_matrix, 3, 4)
print("result:", result)

写在后面

真的很抱歉, 第一次写这种算法博客结果出了这么大的问题,之前都是一些记录BUG的文章,还好同学及时和我说了,主要原因还是自己没有做那么多测试的问题。
有什么可以改进的地方还请批评指正,我会努力改进的!

0
0
查看评论

利用广度优先搜索求最短路径

注:下面是以无权的图为基础的 广度优先搜索:http://blog.csdn.net/u012763794/article/details/51081830 1.问题描述 输入: 输入n个顶点,m条边, 起点的编号 跟着再输入边x,y 输出: 该起点到达各个顶点最少经过几条边 样例: 输...
  • u012763794
  • u012763794
  • 2016-04-09 13:57
  • 2750

用Python实现Dijkstra算法用来寻找两点之间的最短路径 (Implementation of Dijkstra in Python)

下边我贴出的例子是基于GitHub上一个写得较为顺眼的例子,然后自己包了一下,并解析了一下原作的返回内容,使得它符合我的需求:输入一个src-dst pair,返回他们之间的 distance 与 shortest path。废话不多说,有图有真相:可以运行。需要的拿走用就是了。
  • DavyHwang
  • DavyHwang
  • 2015-06-18 21:36
  • 9101

python最短路径算法,基于dijkstra

graph.py    #!/usr/bin/python class Edge(object): def __init__(self, start, end, weight): self.startNodeId = start sel...
  • zlj_vip
  • zlj_vip
  • 2013-12-29 12:47
  • 1243

python实现Dijkstra算法求解图中最短路径距离

继续上一篇博文的内容,这里要做的是Dijkstra算法,与Floyd算法类似,二者的用途均为求解最短路径距离,在图中有着广泛的应用,二者的原理都是老生常谈了,毕竟本科学习数据结构的同学是不可能不学习这两个算法的,所以在这里我也不再累赘,只简单概述一下这个算法的核心思想:     ...
  • Together_CZ
  • Together_CZ
  • 2017-07-07 11:08
  • 1886

python 实现 Dijkstra最短路径问题

Python 实现dijkstra 算法计算最短路径,通过优先队列Q优化
  • yyi_hkust
  • yyi_hkust
  • 2015-11-16 23:02
  • 596

Python-通过Dijkstra计算两点之间的最短路径

文章是基于http://blog.csdn.net/playboyno/article/details/7832437的实现代码进行修改,最终实现计算两点之间的最短路径并把经过的点记录下来。 1.图和链接中的一样。 2.代码 红色为新添加的代码 ''' file: p...
  • xuchenhuics
  • xuchenhuics
  • 2015-01-16 22:43
  • 1212

几种最短路径算的Python实现

最近学习了一些关于最短路径算法的知识,感觉很有意思,但是网路上很多的算法斗志又C或C++的实现方式,很少有Python。于是我就想来自己些个Python最短路径的教程,权当复习自己的知识。
  • tfd0851
  • tfd0851
  • 2016-01-01 23:04
  • 5578

python解决最短路径问题:Floyd-Warshall算法

昨晚做的华为实习生笔试题第三题的解答就涉及到最短路径问题,今天查阅资料l,重新做了一下。 主要思路: 1.根据天气状况更新路线图hmap 2.根据最新的路线图hmap,运用最短路径算法Floyd-Warshall算法,求得任意两城市之间最短路径所必须经过的城市,放在path矩阵中(A矩阵存放对...
  • u012063507
  • u012063507
  • 2017-03-25 20:14
  • 387

boost dijkstra 获得两点直接的最短路径

http://www.xlgps.com/article/301548.html #include #include #include #include #include using namespace boost; // define visitor for discover_v...
  • zhangweilong219
  • zhangweilong219
  • 2018-01-07 15:59
  • 58

图两点间的最短路径,所有路径算法C语言实现

#include #include #include #define INFINITY 32768 //无穷大 #define MAX_VERTEX_NUM 11 //最大顶点数 typedef struct ArCell { int adj; //...
  • mywh
  • mywh
  • 2013-09-06 18:31
  • 4064
    个人资料
    • 访问:48334次
    • 积分:1067
    • 等级:
    • 排名:千里之外
    • 原创:46篇
    • 转载:1篇
    • 译文:2篇
    • 评论:30条
    友情链接
    最新评论