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


Posted in Python onJanuary 17, 2019

前言

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

广度优先搜索

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

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

思路

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

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

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

每一次用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的文章,还好同学及时和我说了,主要原因还是自己没有做那么多测试的问题。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
python高手之路python处理excel文件(方法汇总)
Jan 07 Python
Python实现读取文件最后n行的方法
Feb 23 Python
matplotlib绘制符合论文要求的图片实例(必看篇)
Jun 02 Python
python使用opencv按一定间隔截取视频帧
Mar 06 Python
python write无法写入文件的解决方法
Jan 23 Python
Python集中化管理平台Ansible介绍与YAML简介
Jun 12 Python
pybind11在Windows下的使用教程
Jul 04 Python
Python 保持登录状态进行接口测试的方法示例
Aug 06 Python
Python学习笔记之列表和成员运算符及列表相关方法详解
Aug 22 Python
使用Python爬虫库requests发送表单数据和JSON数据
Jan 25 Python
通过Python实现一个简单的html页面
May 16 Python
numpy的Fancy Indexing和array比较详解
Jun 11 Python
python游戏地图最短路径求解
Jan 16 #Python
python调用百度地图WEB服务API获取地点对应坐标值
Jan 16 #Python
Python3 关于pycharm自动导入包快捷设置的方法
Jan 16 #Python
在Pycharm中自动添加时间日期作者等信息的方法
Jan 16 #Python
解析Python的缩进规则的使用
Jan 16 #Python
在Pycharm中将pyinstaller加入External Tools的方法
Jan 16 #Python
浅谈python3.x pool.map()方法的实质
Jan 16 #Python
You might like
PHP魔术方法之__call与__callStatic使用方法
2017/07/23 PHP
bindParam和bindValue的区别以及在Yii2中的使用详解
2018/03/12 PHP
Javascript 键盘事件的组合使用实现代码
2012/05/04 Javascript
javascript计算当月剩余天数(天数计算器)示例代码
2014/01/09 Javascript
浅谈jQuery异步对象(XMLHttpRequest)
2014/11/17 Javascript
JavaScript函数使用的基本教程
2015/06/04 Javascript
AngularJS基础教程之简单介绍
2015/09/27 Javascript
只需五句话搞定JavaScript作用域(经典)
2016/07/26 Javascript
Js利用prototype自定义数组方法示例
2017/10/20 Javascript
JS 实现获取验证码 倒计时功能
2018/10/29 Javascript
详解nodejs 开发企业微信第三方应用入门教程
2019/03/12 NodeJs
vue项目或网页上实现文字转换成语音播放功能
2020/06/09 Javascript
原生js实现表格翻页和跳转
2020/09/29 Javascript
JS如何实现在弹出窗口中加载页面
2020/12/03 Javascript
pycharm 使用心得(八)如何调用另一文件中的函数
2014/06/06 Python
Python求解平方根的方法
2015/03/11 Python
Python使用Beautiful Soup包编写爬虫时的一些关键点
2016/01/20 Python
Python3.6 Schedule模块定时任务(实例讲解)
2017/11/09 Python
flask-socketio实现WebSocket的方法
2018/07/31 Python
Python 实现子类获取父类的类成员方法
2019/01/11 Python
两个元祖T1=('a', 'b'),T2=('c', 'd')使用匿名函数将其转变成[{'a': 'c'},{'b': 'd'}]的几种方法
2019/03/05 Python
基于Python获取docx/doc文件内容代码解析
2020/02/17 Python
解决Python发送Http请求时,中文乱码的问题
2020/04/30 Python
使用python把xmind转换成excel测试用例的实现代码
2020/10/12 Python
Django集成MongoDB实现过程解析
2020/12/01 Python
python简单实现插入排序实例代码
2020/12/16 Python
结合 CSS3 transition transform 实现简单的跑马灯效果的示例
2018/02/07 HTML / CSS
详解CSS3 filter:drop-shadow滤镜与box-shadow区别与应用
2020/08/24 HTML / CSS
Auchan Direct波兰:欧尚在线杂货店
2016/10/19 全球购物
第一范式(1NF)、第二范式(2NF)和第三范式(3NF)之间的区别是什么?
2016/04/28 面试题
幼儿园教师自我鉴定
2014/03/20 职场文书
岗位竞聘书范文
2014/03/31 职场文书
义和团口号
2014/06/17 职场文书
副校长竞聘演讲稿
2014/09/01 职场文书
2021年最新用于图像处理的Python库总结
2021/06/15 Python
node快速搭建后台的实现步骤
2022/02/18 NodeJs