【算法图解】阅读笔记Day3

本文介绍了广度优先搜索(BFS)和狄克斯特拉算法,用于解决图中的最短路径问题。BFS适用于查找是否存在路径,而Dijkstrasalgorithm则用于找到加权图的最小成本路径,但不适用于负权重边。文章通过Python代码示例解释了这两个算法的工作原理。
摘要由CSDN通过智能技术生成

前言

美好的周末,来看算法图解咯~

广度优先搜索

  • 用图解决最短路径问题的算法被称为广度优先搜索
  • 图由节点组成
  • 用于回答两个问题
    • 第一类问题:从节点A出发,有前往节点B的路径吗?
    • 第二类问题:从节点A出发,前往节点B的哪条路径最短?
  • 队列先进先出(FIFO),栈后进先出(LIFO)
  • python可以用字典键值对表示有向图的结点
    • graph = {}
      graph["you"] = ["alice", "bob", "claire"]
      graph["bob"] = ["anuj", "peggy"]
      graph["alice"] = ["peggy"]
      graph["claire"] = ["thom", "jonny"]
      graph["anuj"] = []
      graph["peggy"] = []
      graph["thom"] = []
      graph["jonny"] = []
  •  算法原理

    • from collections import deque  
      search_queue = deque()  # 创建一个队列
      search_queue += graph["you"]  # 将你的邻居都加入到这个搜索队列中
      
      def person_is_seller(name):  # 检查人的姓名是否以m结尾(芒果销售商)
          return name[-1] == 'm'
      
      while search_queue:  # 只要队列不为空,
          person = search_queue.popleft()  # 就取出其中的第一个人
          if person_is_seller(person):  # 检查这个人是否是芒果销售商
              print person + " is a mango seller!"  # 是芒果销售商
              return True
          else:
              search_queue += graph[person]  # 不是芒果销售商。将这个人的朋友都加入搜索队列
      
      return False  # 如果到达了这里,就说明队列中没人是芒果销售商
  •  还要添加一个数组记录已检查过的人防止死循环
    • def search(name):
          search_queue = deque()
          search_queue += graph[name]
          searched = []  # 这个数组用于记录检查过的人
          while search_queue:
              person = search_queue.popleft()
              if not person in searched:  # 仅当这个人没检查过时才检查
                  if person_is_seller(person):
                      print person + " is a mango seller!"
                      return True
                  else:
                      search_queue += graph[person]
                      searched.append(person)  # 将这个人标记为检查过
          return False
  • 广度优先搜索的运行时间:
    • O(人数 + 边数),这通常写作O(V + E),其中V为顶点(vertice)数,E为边数 

狄克斯特拉算法(Dijkstra’s algorithm)

  • 找出加权图中总权重最小的路径,只适用于有向无环图(directed acyclicgraph,DAG)
  • 四个步骤
  • 如果有负权边,就不能使用狄克斯特拉算法,用贝尔曼-福德算法
  • 算法编写
    • 创建三个散列表,
      • 图和权重,开销(是从起点出发前往该节点需要多长时间)和父节点
    •  
    •  
    • def find_lowest_cost_node(costs):  # 找出开销最低的节点
          lowest_cost = float("inf")  # 表示正无穷
          lowest_cost_node = None
          for node in costs:  # 遍历所有的节点
              cost = costs[node]
              if cost < lowest_cost and node not in processed:  # 如果当前节点的开销更低且未处理过,
                  lowest_cost = cost  # 就将其视为开销最低的节点
                  lowest_cost_node = node
          return lowest_cost_node
      node = find_lowest_cost_node(costs)  # 在未处理的节点中找出开销最小的节点
      while node is not None:  # 这个while循环在所有节点都被处理过后结束
          cost = costs[node]
          neighbors = graph[node]
          for n in neighbors.keys():  # 遍历当前节点的所有邻居
              new_cost = cost + neighbors[n]
              if costs[n] > new_cost:  # 如果经当前节点前往该邻居更近,
                  costs[n] = new_cost  # 就更新该邻居的开销
                  parents[n] = node  # 同时将该邻居的父节点设置为当前节点
          processed.append(node)  # 将当前节点标记为处理过
          node = find_lowest_cost_node(costs)  # 找出接下来要处理的节点,并循环

 后言

道理我都懂,但到时候实现的时候估计又是一脸懵了,无论怎么说,先理解算法思想吧!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值