最佳优先搜索best-find search

2024-09-05 17:36

本文主要是介绍最佳优先搜索best-find search,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

1. 问题

2. 算法

3.代码


1. 问题

考虑下面这个问题:

 我们要找到从Arad到Bucharest的路,最好是最短的路:

2. 算法

这是一个无向有环图,

可以采用最佳优先搜索:

最佳优先搜索的算法可以参考维基百科:

伪代码如下:

// Pseudocode for Best First Search
Best-First-Search(Graph g, Node start)1) Create an empty PriorityQueuePriorityQueue pq;2) Insert "start" in pq.pq.insert(start)3) Until PriorityQueue is emptyu = PriorityQueue.DeleteMinIf u is the goalExitElseForeach neighbor v of uIf v "Unvisited"Mark v "Visited"                    pq.insert(v)Mark u "Examined"                    
End procedure

如果你熟悉广度优先搜索,那么上面的代码也没什么难度。

该算法最关键的点是如何构造优先队列中的“优先”策略,一种简单的办法就是选取当前所有访问点中最近的相邻点:

procedure GBS(start, target) is:mark start as visitedadd start to queuewhile queue is not empty do:current_node ← vertex of queue with min distance to targetremove current_node from queueforeach neighbor n of current_node do:if n not in visited then:if n is target:return nelse:mark n as visitedadd n to queuereturn failure

显然上面的BFS是一种贪婪算法,每次选取最优的近邻点是一种“短视”,虽然如此,他仍是一种可行的算法。

该算法最坏的复杂度是 O(n*logn) ,其中n是节点的总数。在最坏的情况我们需要访问所有节点,然后我们构造的堆,每次添加删除元素时复杂度为:O(logn)   

算法的性能显然与我们选择什么样的代价函数有直接关系。

3.代码

首先是节点类

# -*- coding: utf-8 -*-
"""
Created on Wed Sep  4 15:56:35 2024@author: Paul
"""class Node:def __init__(self,name):self._name=nameself._children=[]def __repr__(self):return 'Node({!r})'.format(self._name)def add_child(self,node):self._children.append(node)def __iter__(self):return iter(self._children)def __eq__(self, other):return self._name==other._namedef Childrens(self):return self._children()

优先队列:

# -*- coding: utf-8 -*-
"""
Created on Wed Sep  4 16:03:33 2024@author: Paul
"""import heapqclass PriorityQueue:def __init__(self):self._queue=[]self._index=0def push(self,item,priority):heapq.heappush(self._queue, (priority,self._index,item))self._index+=1def pop(self):return heapq.heappop(self._queue)[-1]   #弹出itemdef empty(self):              #判断是否为空return True if not self._queue else False

数据节点:

这里只选取到BuCharest城市的数据,该城市是访问Urziceni和Giurgiu后续的点必经之路。

这些城市:

cities=['Arad','Zerind','Oradea','Sibiu','Fagaras','Bucharest',
        'Pitesti','Rimnicu','Craiova','Drobeta','Mehadia','Lugoj',
        'Timisoara']

cities=['Arad','Zerind','Oradea','Sibiu','Fagaras','Bucharest','Pitesti','Rimnicu','Craiova','Drobeta','Mehadia','Lugoj','Timisoara']Nodes=[Node(name) for name in cities]     #12个节点
dist_mat=[[] for i in range(len(cities))]def addedge(start,end,dist):x=cities.index(start)y=cities.index(end)dist_mat[x].append((y,dist))dist_mat[y].append((x,dist))addedge('Arad', 'Zerind', 75)
addedge('Arad', 'Sibiu', 140)
addedge('Arad', 'Timisoara', 118)
addedge('Zerind','Oradea',71)
addedge('Oradea', 'Sibiu', 151)
addedge('Sibiu', 'Fagaras', 99)
addedge('Sibiu', 'Rimnicu',80)
addedge('Fagaras', 'Bucharest', 211)
addedge('Bucharest', 'Pitesti', 101)
addedge('Pitesti', 'Rimnicu', 97)
addedge('Pitesti', 'Craiova', 138)
addedge('Craiova', 'Rimnicu', 146)
addedge('Craiova', 'Drobeta', 120)
addedge('Drobeta', 'Mehadia', 75)
addedge('Mehadia', 'Lugoj', 70)
addedge('Lugoj', 'Timisoara', 111)for index,city in enumerate(Nodes):for t in dist_mat[index]:city.add_child(Nodes[t[0]])

每个节点与其相邻节点关系如下:

Node('Arad') =>[Node('Zerind'), Node('Sibiu'), Node('Timisoara')]
Node('Zerind') =>[Node('Arad'), Node('Oradea')]
Node('Oradea') =>[Node('Zerind'), Node('Sibiu')]
Node('Sibiu') =>[Node('Arad'), Node('Oradea'), Node('Fagaras'), Node('Rimnicu')]
Node('Fagaras') =>[Node('Sibiu'), Node('Bucharest')]
Node('Bucharest') =>[Node('Fagaras'), Node('Pitesti')]
Node('Pitesti') =>[Node('Bucharest'), Node('Rimnicu'), Node('Craiova')]
Node('Rimnicu') =>[Node('Sibiu'), Node('Pitesti'), Node('Craiova')]
Node('Craiova') =>[Node('Pitesti'), Node('Rimnicu'), Node('Drobeta')]
Node('Drobeta') =>[Node('Craiova'), Node('Mehadia')]
Node('Mehadia') =>[Node('Drobeta'), Node('Lugoj')]
Node('Lugoj') =>[Node('Mehadia'), Node('Timisoara')]
Node('Timisoara') =>[Node('Arad'), Node('Lugoj')]

最后BFS如下:

# -*- coding: utf-8 -*-
"""
Created on Wed Sep  4 16:37:37 2024@author: Paul
"""from node import Node
from priorityqueue import PriorityQueuedef BFS(mat,start,dest):q=PriorityQueue()q.push(start, 0)visited=[start]while not q.empty():u=q.pop()print(u)if u==dest:return Trueelse:for city,dist in mat[Nodes.index(u)]:child=Nodes[city]if child not in visited:visited.append(child)q.push(child, dist)return False

运行BFS结果如下:

Node('Arad')
Node('Zerind')
Node('Oradea')
Node('Timisoara')
Node('Lugoj')
Node('Mehadia')
Node('Drobeta')
Node('Craiova')
Node('Pitesti')
Node('Bucharest')

访问路径如下:

     算法每次选取最近的节点,因此我们没有得到最优解,要想得到最优解,需要对算法进行改造,使之称为启发式算法,我会在后续章节介绍一二。

参考链接:

BFS维基百科:Best-first search - Wikipedia

geek for geeks: Best First Search (Informed Search) - GeeksforGeeks

这篇关于最佳优先搜索best-find search的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!


原文地址:
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.chinasem.cn/article/1139618

相关文章

Vue 2 项目中配置 Tailwind CSS 和 Font Awesome 的最佳实践举例

《Vue2项目中配置TailwindCSS和FontAwesome的最佳实践举例》:本文主要介绍Vue2项目中配置TailwindCSS和FontAwesome的最... 目录vue 2 项目中配置 Tailwind css 和 Font Awesome 的最佳实践一、Tailwind CSS 配置1. 安

Spring Boot 常用注解详解与使用最佳实践建议

《SpringBoot常用注解详解与使用最佳实践建议》:本文主要介绍SpringBoot常用注解详解与使用最佳实践建议,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要... 目录一、核心启动注解1. @SpringBootApplication2. @EnableAutoConfi

在 Spring Boot 中实现异常处理最佳实践

《在SpringBoot中实现异常处理最佳实践》本文介绍如何在SpringBoot中实现异常处理,涵盖核心概念、实现方法、与先前查询的集成、性能分析、常见问题和最佳实践,感兴趣的朋友一起看看吧... 目录一、Spring Boot 异常处理的背景与核心概念1.1 为什么需要异常处理?1.2 Spring B

Python使用getopt处理命令行参数示例解析(最佳实践)

《Python使用getopt处理命令行参数示例解析(最佳实践)》getopt模块是Python标准库中一个简单但强大的命令行参数处理工具,它特别适合那些需要快速实现基本命令行参数解析的场景,或者需要... 目录为什么需要处理命令行参数?getopt模块基础实际应用示例与其他参数处理方式的比较常见问http

Java Response返回值的最佳处理方案

《JavaResponse返回值的最佳处理方案》在开发Web应用程序时,我们经常需要通过HTTP请求从服务器获取响应数据,这些数据可以是JSON、XML、甚至是文件,本篇文章将详细解析Java中处理... 目录摘要概述核心问题:关键技术点:源码解析示例 1:使用HttpURLConnection获取Resp

Java Optional的使用技巧与最佳实践

《JavaOptional的使用技巧与最佳实践》在Java中,Optional是用于优雅处理null的容器类,其核心目标是显式提醒开发者处理空值场景,避免NullPointerExce... 目录一、Optional 的核心用途二、使用技巧与最佳实践三、常见误区与反模式四、替代方案与扩展五、总结在 Java

Spring Boot循环依赖原理、解决方案与最佳实践(全解析)

《SpringBoot循环依赖原理、解决方案与最佳实践(全解析)》循环依赖指两个或多个Bean相互直接或间接引用,形成闭环依赖关系,:本文主要介绍SpringBoot循环依赖原理、解决方案与最... 目录一、循环依赖的本质与危害1.1 什么是循环依赖?1.2 核心危害二、Spring的三级缓存机制2.1 三

Python 中的 with open文件操作的最佳实践

《Python中的withopen文件操作的最佳实践》在Python中,withopen()提供了一个简洁而安全的方式来处理文件操作,它不仅能确保文件在操作完成后自动关闭,还能处理文件操作中的异... 目录什么是 with open()?为什么使用 with open()?使用 with open() 进行

MySQL中FIND_IN_SET函数与INSTR函数用法解析

《MySQL中FIND_IN_SET函数与INSTR函数用法解析》:本文主要介绍MySQL中FIND_IN_SET函数与INSTR函数用法解析,本文通过实例代码给大家介绍的非常详细,感兴趣的朋友一... 目录一、功能定义与语法1、FIND_IN_SET函数2、INSTR函数二、本质区别对比三、实际场景案例分

Spring Boot 配置文件之类型、加载顺序与最佳实践记录

《SpringBoot配置文件之类型、加载顺序与最佳实践记录》SpringBoot的配置文件是灵活且强大的工具,通过合理的配置管理,可以让应用开发和部署更加高效,无论是简单的属性配置,还是复杂... 目录Spring Boot 配置文件详解一、Spring Boot 配置文件类型1.1 applicatio