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 内置函数小结
Aug 09 Python
python正则实现提取电话功能
Feb 24 Python
python3+PyQt5实现拖放功能
Apr 24 Python
python 重命名轴索引的方法
Nov 10 Python
对pandas的算术运算和数据对齐实例详解
Dec 22 Python
详解DeBug Python神级工具PySnooper
Jul 03 Python
Django对数据库进行添加与更新的例子
Jul 12 Python
Python 实现大整数乘法算法的示例代码
Sep 17 Python
简单了解python装饰器原理及使用方法
Dec 18 Python
pytorch程序异常后删除占用的显存操作
Jan 13 Python
用python实现前向分词最大匹配算法的示例代码
Aug 06 Python
python中四舍五入的正确打开方式
Jan 18 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
Breeze 文章管理系统 v1.0.0正式发布
2006/12/14 PHP
一些 PHP 管理系统程序中的后门
2009/08/05 PHP
PHP图像处理之imagecreate、imagedestroy函数介绍
2014/11/19 PHP
PHP socket 模拟POST 请求实例代码
2016/07/18 PHP
PHP基于双向链表与排序操作实现的会员排名功能示例
2017/12/26 PHP
一个javascript图片阅览组件
2010/11/09 Javascript
js循环改变div颜色具体方法
2013/06/25 Javascript
JavaScript获取onclick、onchange等事件值的代码
2013/07/22 Javascript
基于jquery实现的自动补全功能
2015/03/12 Javascript
jQuery扩展_动力节点Java学院整理
2017/07/05 jQuery
如何理解Vue的render函数的具体用法
2017/08/30 Javascript
Vue在 Nuxt.js 中重定向 404 页面的方法
2019/04/23 Javascript
Vue实现剪贴板复制功能
2019/12/31 Javascript
javascript实现贪吃蛇小游戏
2020/07/28 Javascript
vue用ant design中table表格,点击某行时触发的事件操作
2020/10/28 Javascript
Python中的模块和包概念介绍
2015/04/13 Python
Swift中的协议(protocol)学习教程
2016/07/08 Python
Python2.7基于淘宝接口获取IP地址所在地理位置的方法【测试可用】
2017/06/07 Python
Python 3.x读写csv文件中数字的方法示例
2017/08/29 Python
Python基于Flask框架配置依赖包信息的项目迁移部署
2018/03/02 Python
十个Python练手的实战项目,学会这些Python就基本没问题了(推荐)
2019/04/26 Python
详解将Python程序(.py)转换为Windows可执行文件(.exe)
2019/07/19 Python
python 命令行传入参数实现解析
2019/08/30 Python
Python matplotlib画图时图例说明(legend)放到图像外侧详解
2020/05/16 Python
python和c语言哪个更适合初学者
2020/06/22 Python
python 使用OpenCV进行简单的人像分割与合成
2021/02/02 Python
希腊品牌鞋类销售网站:epapoutsia.gr
2020/03/18 全球购物
拓展策划方案
2014/06/03 职场文书
银行求职自荐书
2014/06/25 职场文书
个人批评与自我批评发言稿
2014/09/28 职场文书
十岁生日答谢词
2015/01/05 职场文书
投标承诺函范文
2015/01/21 职场文书
魂断蓝桥观后感
2015/06/10 职场文书
导游词之山东八仙过海景区
2019/11/11 职场文书
mysql字符串截取函数小结
2021/04/05 MySQL
MySQL 常见的数据表设计误区汇总
2021/06/07 MySQL