最短路径算法之AStar算法(一) AStar算法的证明

2023-05-16

本文并不试图对A Star算法进行一个入门式的讲解,因为光是那个讲解就有可能会占据很长的篇幅,而且网上已经有讲解的文章,讲的肯定比我好。所以,本文是面向已经对A Star算法有了一定了解的人。如果各位对A Star算法还不睡很了解,那么请参考我下面列出的几篇文章:

 

1,http://apps.hi.baidu.com/share/detail/16593767

     这篇文章详细讲解了A Star算法,是一片很好的入门文章。读者如果有兴趣还可以参看它的英文原文。

 

2,http://blog.csdn.net/sworder_001/archive/2006/09/27/1297501.aspx

    这篇文章有A Star算法的伪代码,和上面文章的伪代码有所不同,细心的读者一定可以看出来。本文稍后会讨论这个不同。

 

好了,到了这里,我假设读者已经对S Star算法有了较好的理解。

 

在讲解A Star算法前,先定义一下文章中使用的符号和术语。

图G代表了某个要在其上寻找最短路径的图,start为起点,end为终点。
有某条路径path,其上的某两点为M和N,则令符号Ppath(M-N)为在路径path上从点到点N的路径值。那么,Ppath(start-end)就是路径path的值。
α(N)为在图G中从start到N的最短路径值。 
β(N)为G图中从N到end的最短距离。
w(x,y)为边(x,y)的权值。
对于某条有向边(M,N),M是N的前驱节点,N是M的后继节点。 

 

AStar算法是从起点开始一步步的往终点探索。他有两个链表open链表和close链表。每探索(本文称之为“扩展”)一个点N时,就获取了N的所有的后继节并且把他们放到open链表中,并且把点N放到close链表中。AStar算法每从open链表中选取一个点进行扩展,选取的原则就是每个节点的评估函数。
评估函数F(N)=G(N)+H(N)。通过评估函数,每个节点都有一个评估值。G(N)代表了在一步步扩展的过程中,从start到点N的距离,H(N)代表了从点N到end的最短距离的估计值,注意,这里说的是估计值,当然是因为最短距离无法得知,所以只能估计了。通过这个评估函数我们可以看出来,节点的评估值代表了通过该节点从起点到终点的最短路径的一个估计值。
H函数随着图的不同而不同。

 

AStar算法的伪代码如下:
假设对于某个节点N而言,H函数值为H(N)。
建立一个数据结构Node:
struct Node{
    int g;   //该节点的g值
    int h;   //该节点的h值
    int f;   //该节点的f值
    Node* pre;  //该节点的前驱节点
};


AStar_Search(){
    struct  Node  start_node;
    start_node.g = 0;
    start_node.h = H(start);
    start_node.f = start_node.h;
    start_node.pre = NULL;

 

    OPEN链表 = [start_node]; CLOSE链表 = [];

 

    while ( OPEN链表非空 ) {
        从OPEN链表中取得F值最小的Node,称之为x_node,对应的节点称之为为x;
        从OPEN链表中删除x_node;

 

        if (x是end节点){
            根据每个节点对应的node结构的pre指针,返回路径;
        }

 

        for (x的每一个后继节点y){
            struct  Node  y_node;
            y_node.g = x_node.g+w(x,y);
            y_node.h = H(y);
            y_node.f = y_node.g+y_node.h;
            y.pre = x_node;

 

            if( y不在OPEN表 and 不在CLOSE表中){
                把y_node放到OPEN表中;
            }else  if( y在OPEN表中){
                取出OPEN表中的y节点对应的Node结构,称之为y_open;

 


                if( y_node.f小于y_open.f) {               //程序注意点1
                    y_open.g=y_node.g;
                    y_open.h=y_node.h;
                    y_open.f =y_node.f;
                    y_open.pre = y_node.pre;
                }
            }else{              //y在CLOSE表中
                取出CLOSE表中的y节点对应的Node结构,称之为y_close;


                if(y_node.f小于y_close.f){              //程序注意点2
                    将y_close从CLOSE链表中删除
                    把y_node放到OPEN表中;
                }
            }
        }  //end  for

 

 

        将x_node放入到CLOSE表中;
    }    //end  while
}    // end  AStar_Search

 

设点N为图中的一个点,如果H(N)<= β(N),那么用A Star算法找出来的路径就是最短路径。否则,只能是近似的最短路径,而并非最短路径。

 

个人认为,算法中有两个隐含的前提:
1. H(end)=0,也就是说,终点的H函数的估计值为0,这是显而易见的。
2. H函数不会随着算法的进行而发生变化,也就是说,对于某个节点N而言,H(N)的值是不变的。

 

我们来证明这个算法,就是说当H(N)<= β(N)时,算法找出来的是最短路径。

 

引理1:令某条路径stp是图G中的最短路径,点N是这条路上的任意一点,则Pstp(start-N)= α(N)。
证明很简单,假设从start到点N存在一条更短的路径,其路径值为P(start-N),就是说P(start-N)< Pstp(start-N)。Pstp(start-end)= Pstp(start-N)+ Pstp(N-end)。那么用这条更短的路径替换掉路径stp中从起点start到点N的路径,得到一个新的路径,令其为stp’。那么Pstp' (start-end)= P(start-N)+ Pstp(N-end)< Pstp(start-N)+ Pstp(N-end)= Pstp(start-end)。因此,这个新的路径的值肯定更短,这与stp是最短路径矛盾,因此,Pstp(start-N)= α(N)。

 

引理2:令某条路径stp是最短路径,N是这条路上的任意一点,则Pstp(N-end)=β(N)
证明方式和引理1相同。

 

引理3:令某条路径stp是最短路径,N是这条路上的任意一点,每个节点的H函数值不变,令G(N)= Pstp(start-N),则此时得到的F(N)为最小值,并且,如果H(N)<=β(N),则F(N)<= Pstp (start-end)。
证明很简单,F=G+H。在H函数值不变的前提下,F函数值的大小就看就看G函数值的大小。根据引理1,Pstp(start-N)为从start到点N的最短值。因此,F(N)= Pstp(start-N)+H(N)为最小值。Pstp (start-end)= Pstp (N-S1)+ Pstp (N-end)= Pstp (N-S1)+ β(N)(根据引理2)>= Pstp (N-S1)+ H(N)=F(N)。

 

现在,简单的证明一下这个算法,就是说对于图中的任意一个节点node而言,令H(node)<= β(node),则找出的路径是最短路径。以下的证明建立在前面所说的两个前提之下。

 

用反证法。假设该算法不正确,通过该算法找出了一条路径,设其为astar,实际的最短路径为stp。 那么令Pastar (start-end)> Pstp (start-end)。因为如果Pastar (start-end)=Pstp(start-end),那么该算法没有错误,只不过是找到了另外一条最短路径。令Pastar (start-end)=M,Pstp (start-end)=N,M>N。
因为找出的路径是astarh并且其路径值是M,所以当扩展end节点时其F值是M并且是open链表中F值最小的节点。

令stp路径为start-S1-S2-……-Sk-end。从S1到Sk的各个节点的最小的F值依次是F1、F2、……、Fk。根据引理3,这些F值都小于M。

 

好的,我们现在看一下S1节点。AStar算法从start开始,扩展start节点,start后继的节点中包括S1,因此S1被放置到了open链表中。G(S1)= Pstp (start-S1)。根据引理1,这也是从start到S1的最短距离,因此G(S1)已经达到最小值,不会被再次改变。根据引理3,此时,S1节点的F值F(S1)= F1<=N<M。因此,根据AStar算法,我们可以得出下面这个结论,我们称之为结论1
在以F1为F值扩展S1节点以前,不可能以M为F值扩展end节点。

 

现在我们假设节点Sm以Fm为F值进行了扩展,1<=m<=k。下面看看节点Sm+1。如果m=k,那么Sm+1就是end节点。
扩展Sm节点时,因为Sm+1节点是其后继节点,则计算Sm+1节点的F值为F(Sm+1)=G(Sm+1)+H(Sm+1)=G(Sm)+w(Sm,Sm+1)+ H(Sm+1)。根据引理3,G(Sm)= Pstp(start-Sm) ,因此,F(Sm+1)= Pstp(start-Sm)+w(Sm,Sm+1)+ H(Sm+1)。因为Sm节点以及Sm+1节点都是最短路径stp上的节点,很显然,Pstp(Sm)+w(Sm,Sm+1)= Pstp(start-Sm+1)。因此,F(Sm+1)= Pstp(start-Sm+1)+ H(Sm+1)。再次根据引理3,F(Sm+1)是Sm+1节点中所有可能的F值中的最小值,并且该值不会在以后的计算中被再次改变,因此F(Sm+1)= Fm+1
扩展完毕Sm节点以后,Sm+1节点的位置只可能是两种:open链表或者是close链表。如果Sm+1节点在open链表中,则它的F值只可能是最小的F值Fm+1。在以Fm+1为F值扩展Sm+1节点以前,不可能以M为F值扩展end节点。如果Sm+1节点在close链表中,那么根据AStar算法,在close链表中的Sm+1节点的老的F值F'(Sm+1)<= Fm+1。因为,对于Sm+1节点而言Fm+1已经是最小的F值了,因此F'(Sm+1)= Fm+1。也就是说,该Sm+1节点已经被以Fm+1为F值进行扩展过了,并且扩展时F值为最小的F值Fm+1。
至此,我们可以得出一个结论,称之为结论2
如果在最短路径stp上的某个节点Sm以最小的F值Fm被扩展,那么在其后继节点Sm+1被以Fm+1为F值进行扩展以前,不可能以M为F值扩展end节点。

 


当Sk节点以Fk为F值进行扩展时,end节点作为其后继节点,根据和上面相同的推理过程,可以得到其F值为Pstp(start-Sk)+w(Sk,end)+ H(end)= Pstp(start-end)+ H(end)= Pstp(start-end)=N<M(H(end)等于0),并且N也是end节点最小的F值。end节点不可能在close链表中否则算法早就结束了,则end节点在open链表中并且其F值只可能是N。因为N小于M,根据AStar算法end节点的F值不可能变成M,因此,找出的AStarPath路径是不存在的。至此证明完毕。

 

AStar算法的H函数是AStar算法的核心,H函数估计的准确与否直接关系到了算法的效率和执行时间。我们假想一下,如果H函数的估计完全准确,那么每个最短路径上的节点的F值都是最小的,那么遵循着最小的F值一直找下去很快就可以得到最短路径了。如果H函数的估计误差很大,使得某个F值很小的节点实际上到终点的路程很远,那么算法就可能在错误的了路径上探索较长时间,然后再回到正确的路径上探索。因此,如果使用了AStar算法,H函数的设计一定要谨慎,否则该算法很可能达不到你当初设想的性能要求。


结合结论1和结论2,在以M为F值扩展end节点以前,S1节点必须以F1为F值进行扩展,因而,S2节点必须以F2为F值进行扩展,因而S3节点必须以Fe为F值进行扩展,一直到Sk节点必须以Fk为F值进行扩展。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

最短路径算法之AStar算法(一) AStar算法的证明 的相关文章

  • CTF竞赛介绍及刷题网址更新---2020.08

    CTF xff08 Capture The Flag xff09 中文一般译作夺旗赛 xff0c 在网络安全领域中指的是网络安全技术人员之间进行技术竞技的一种比赛形式 CTF起源于1996年DEFCON全球黑客大会 xff0c 以代替之前黑
  • VS2008与Matlab混合编程设置

    VS2008 与MATLAB R2009b 混合编程环境配置 一 xff0c VS2008 中的函数调用matlab的写好的函数 1 Matlab 生成 DLL 1 1 编译器的安装 实验环境 xff1a XP 32 位机MATLAB R2
  • System.console().readPassword() java.lang.NullPointerException

    java核心技术 卷I 书籍中有关 java io Console 类的1个示例 System console readLine 与 System console readPassword 在 idea 中运行出现 java lang Nu
  • Linux man中文手册的安装与使用

    概要 xff1a 在 ubuntu 20 04 中下载 安装使用 man 中文手册 文章目录 linux shell命令学习法宝 man 手册man中文手册的下载 安装及环境变量的配置下载安装环境变量配置及 cman 命令使用 man 中文
  • X window selection --- xclip

    原文 英文 url xff1a https encyclopedia thefreedictionary com X 43 Window 43 selection 本文为笔者的翻译 xff0c 红色部分为笔者增加的批注 文章目录 Activ
  • linux安装xclip实现终端与剪贴板之间的通道

    概要 xff1a ubuntu 20 04 通过安装 xclip 来实现终端与剪贴板之间的数据通道 xff1a xclip 类似 dos 中的 clip命令 xff0c xclip 可将命令执行的结果保存到剪贴板 xff0c 还允许将文件的
  • java中GBK与UTF-8编码的转换

    文章目录 java源文件中中文字符的编码的问题UTF 8和GBK格式的文件相互转换java实现文件编码的转换 java不同编码的字节数组的转换Java判断文件编码格式对于UTF 8格式文件的判断 xff1a 利用cpdetector开源库确
  • GBK编码表

    全国信息技术标准化技术委员会 汉字内码扩展规范 GBK Chinese Internal Code Specification 1 0 版 xff08 按编码顺序排列 xff09 其编码范围 xff1a 8140 xff0d FEFE xf
  • dll文件下载网址

    https cn dll files com
  • windows中dos命令汇总及获取管理员权限

    文章目录 windows 获取管理员权限的2种方式runas 用法 windows dos 命令行语法项windows dos命令总述 windows dos命令详细介绍 win7及以前 微软官网 windows dos命令详细介绍 win
  • windows比cmd更强大的 WMIC命令使用详解

    文章目录 什么是wmic WMIC能做什么 WMIC命令使用帮助文档WMIC命令使用实例wmic的运行方式可以有两种法1 显示进程的详细信息2 停止 暂停和运行服务功能3 显示出BIOS信息4 停止进程的操作5 连接远程电脑6 BIOS 基
  • 编程意识——宏定义封装多个函数参数

    作者 釜薪君 公众号 嵌入式杂牌军 文章目录 前言一 这种意识的来源二 实现源码分析1 函数调用2 宏定义部分3 函数实现4 宏替换后的函数调用 总结 前言 今天带小伙伴们分析一段不错的代码 xff0c 学习一下关于宏封装的一种意识 xff
  • DSP28335的SCI的FIFO中断使用心得

    自学了一段时间的DSP28335的串口设置 xff0c 写下来帮助更多的新手 xff0c 遇到了很多问题也记录一些解决办法 以下全都是我个人的理解 xff0c 可能说的不对 xff0c 大家讨论 1 关于为什么必须用FIFO 一般的DSP系
  • 51单片机堆栈深入剖析

    用C语言进行MCS51系列单片机程序设计是单片机开发和应用的必然趋势 Keil公司的C51编译器支持经典8051和8051派生产品的版本 xff0c 通称为Cx51 应该说 xff0c Cx51是C语言在MCS51单片机上的扩展 xff0c
  • 基于ros_arduino_bridge的智能小车----上位机篇

    基于ros arduino bridge的智能小车 上位机篇 基于ros arduino bridge的智能小车 硬件篇 基于ros arduino bridge的智能小车 下位机篇 ros arduino bridge文件系统 xff08
  • 基于ros_arduino_bridge的智能小车----下位机篇

    基于ros arduino bridge的智能小车 下位机篇 参考文章 xff1a 基于ros arduino bridge的智能小车 上位机篇 基于ros arduino bridge的智能小车 硬件篇 下位机部分实际上可以视作完全独立的
  • 【命令】Python执行命令超时控制【原创】

    目录 参考 概要 方案 方案一 xff1a os system 方案二 xff1a os popen 方案三 xff1a subprocess check output 方案四 xff1a subprocess Popen 方案五 xff1
  • nRF52 Mesh开发 (2) SDK例程Light_switch server 添加一个element控制开发板其他LED灯

    server文件结构 xff1a 使用SEGGER编译的话直接打开 emProject文件即可 xff1b img文件中包含程序运行过程图 xff1b include文件包含该例程下的头文件 xff1b 2 具体操作 xff1a 在main
  • nRF52 Mesh开发 (3) MESH Sensor Server/Client Models详解与实现

    MESH Sensor Model 实现 MESH Spec规定的 Sensor Model 标准传感器状态传感器描述传感器参数设置传感器cadence传感器数据 传感器可发送和接收的消息Sensor Server Client Model
  • Telink Mesh 开发(1)调试log打印

    Telink Mesh SDK 调试log打印 Telink 官网论坛建议使用GPIO模拟串口打印log xff0c 推荐阅读Telink官网发布的最新SDK使用手册 xff0c 更新了不少东西 一 使用串口打印log1 使能uart lo

随机推荐

  • 蓝牙Mesh基础(3)蓝牙Mesh协议--总览

    蓝牙Mesh协议 总览Bearer Layer xff08 承载层 xff09 Network Layer xff08 网络层 xff09 Low Transport Layer xff08 下层传输层 xff09 Upper Transp
  • 蓝牙Mesh基础(9)设备配网

    设备配网 xff08 启动配置 xff09 设备配网过程配网PDU配网PDU如何传输呢 设备配网过程 首先 xff0c 需要配网的设备先进行未配网广播 xff0c 这个广播不同于普通的ble广播 xff0c 广播数据结构类型 xff08 A
  • 弱网络环境模拟--树莓派搭建ATC

    弱网络环境模拟 树莓派搭建ATC 1 硬件和系统2 搭建过程3 遇到的问题1 Failed to start hostapd service Unit hostapd service is masked2 django python版本问题
  • OpenCV双目相机测距程序

    本文主要分享一个双目测距的实现程序 xff0c 用的bumblebee2相机 使用的OpenCV自带的BM算法 在OpenCV3中 xff0c StereoBM算法发生了比较大的变化 xff0c StereoBM被定义为纯虚类 xff0c
  • stm32 printf 串口输出

    在使用STM32调试时 xff0c 经常使用串口发送信息 xff0c 为了方便调试与串口发送信息 xff0c 用printf xff08 xff09 函数实现通过串口打印信息 1 添加包含printf xff08 xff09 函数的头文件
  • 【slighttpd】基于lighttpd架构的Server项目实战(7)—http-parser

    对于http服务器 xff0c http request的解析是比较麻烦的 xff0c 由于我们的重点并不在这上面 xff0c 所以这一部分不打算自己编写 xff0c 而是使用开源的http parser库 xff0c 下面我们将使用该库来
  • C#实现以图搜图

    朋友们 xff0c 如需转载请标明出处 xff1a http blog csdn net jiangjunshow 前言 最近在逛淘宝时发现了淘宝的图片搜索功能 xff0c 可能是我太Low了这个技术点已经实现很长时间了 想想自己能不能实现
  • 床长人工智能教程 - 前言

    朋友们 如需转载请标明出处 xff1a http blog csdn net jiangjunshow 人工智能被认为是一种拯救世界 终结世界的技术 毋庸置疑 xff0c 人工智能时代就要来临了 xff0c 科幻电影中的场景将成为现实 xf
  • 如何做接口测试呢?接口测试有哪些工具【小白都会系列】

    回想入职测试已经10年时间了 xff0c 初入职场的我对于接口测试茫然不知 后来因为业务需要 xff0c 开始慢慢接触接口测试 从最开始使用工具进行接口测试到编写代码实现接口自动化 xff0c 到最后的测试平台开发 回想这一路走来感触颇深
  • C++有限状态自动机解析HTTP协议

    一 HTTP请求报文格式 HTTP请求报文主要由四部分组成 xff0c 分别为请求头 请求行 空行 请求体 xff1b 请求方法 请求方法包括GET HEAD PUT POST TRACE OPTIONS DELETE等 xff1b xff
  • 解析URL

    简介 在github有轮子http parser解析器 小的就不再造轮子了 xff0c 哈哈 xff08 造这个轮子真不是一时半会的事 xff09 目前该解析器用于nodejs的http解析 xff0c 另还有大家熟知的tcpflow 以及
  • ubuntu 串口调试助手

    ubuntu 下的串口调试助手推荐有两个 PuTTY 和 CuteCom PuTTY 除了串口通讯功能外还有 SSH 和 Telnet 等功能 CuteCom 只能用于串口通讯 但串口界面更友好 安装串口工具 ubuntu 标准安装源中包含
  • 数据的存储(1):字节序与比特序

    前言 在计算机的发展过程中 xff0c 由于不同硬件体系在数据高低有效位及存储方式理解上的差异 xff0c 出现了大端和小端这两种截然相反的对数据的位进行解释的模式 大小端模式本身没有优劣之分 xff0c 但我们在开发过程中 xff0c 需
  • [C/C++后端开发学习] 11 实现一个简单的HTTP服务器

    文章目录 实现GET方法约定GET时URI的格式状态机与websocket协议兼容实现几个辅助函数GET请求一个html页面 一张图片或一个PDF文件 实现POST方法实现一个简单的服务框架POST请求报文处理的代码块POST响应报文处理的
  • C++ Primer Plus习题及答案-第六章

    习题选自 xff1a C 43 43 Primer Plus 第六版 内容仅供参考 xff0c 如有错误 xff0c 欢迎指正 1 简单文件输入 输出 xff08 写入到文本文件中 xff09 对于文件输入 xff0c C 43 43 使用
  • 航模电池-LiPo锂聚合物电池(未完待续)

    一 外形 1 一般有几个电芯 xff0c 就是几 S xff0c 比如三个电芯就是3S 2 从电池上 xff0c 会引出两组导线 xff0c 一组细的 xff0c 一组粗的 细的一组 xff0c 由一根红线和若干根黑线组成 xff0c 最前
  • visual studio 编译C++程序,加快编译速度

    网上很多有关于选择预编译选项出现 xff0c fatal error C1083 无法打开预编译头文件 pch No such file or directory xff0c 这样的错误 xff0c 好多人会选择直接不使用预编译选项 如果工
  • C++中标准名称空间出错(cout,cin,endl是一个未知标识符)

    相信有很多小伙伴刚刚学习C 43 43 都有出现cout cin endl为未知标识符 原因是 xff1a lt iostream gt 头文件没有namespace std库 解决方法有3种 xff0c 如下 方法1 xff1a 加 us
  • C++源文件编译过程

    对于C 43 43 源文件 xff0c 从文本到可执行文件一般需要四个过程 xff1a 预处理阶段 编译阶段 汇编阶段 链接阶段 预处理阶段 xff1a 对源代码文件中文件包含关系 xff08 头文件 xff09 预编译语句 xff08 宏
  • 最短路径算法之AStar算法(一) AStar算法的证明

    本文并不试图对A Star算法进行一个入门式的讲解 xff0c 因为光是那个讲解就有可能会占据很长的篇幅 xff0c 而且网上已经有讲解的文章 xff0c 讲的肯定比我好 所以 xff0c 本文是面向已经对A Star算法有了一定了解的人