智能驾驶规划控制理论学习02-基于搜索的路径规划方法

目录

一、路径搜索问题

二、图论基础

三、图搜索方法

1、广度优先搜索(BFS)

bfs与dfs的区别

bfs的搜索过程        

bfs的算法实现

2、迪杰斯特拉算法(Dijkstra)

核心思想

优先级队列

Dijkstra搜索过程

Dijkstra优缺点分析

3、A*算法

核心思想

A*搜索过程        

启发式函数

总结

动态规划


一、路径搜索问题

        当我们要搜索一个从起到到终点的最优路径时,要思考何为最优?是从距离角度、时间角度还是其他方面。为了找到一条这样的路径,我们通常会使用一种图像搜索算法,这样地图就可以作为一个图表进行使用。

        对于这种路径搜索问题,将图表上的一系列位置作为节点、它们之间的连线以及起点终点(拓扑地图信息)作为输入,得到的输出是由节点和边构成的网格地图。

二、图论基础

        在图论中可以将图简单分为无向图(Undirected Graph)、有向图(Directed Graph)和权重图(Weighted Graph)。

         在图论中,图由顶点(vertices)和边(edges)组成。顶点代表图中的个体或实体,而边表示顶点之间的关系或连接。这种连接可以是有向的或无向的,具体取决于图的类型和定义。

        在图论中,图的权(Weight)指的是在图的边上赋予的一个数值或度量,用于表示顶点之间的关系或连接的强度、距离、成本等信息。

三、图搜索方法

        本节主要介绍图搜索中常用的算法:广度优先算法(BFS)、迪杰斯特拉算法和A*算法。

1、广度优先搜索(BFS)

bfs与dfs的区别
  • bfs是先把本节点所连接的所有节点遍历一遍,走到下一个节点的时候,再把连接节点的所有节点遍历一遍,搜索方向更像是四面八方的搜索过程。
  • 深度优先搜索是向一个方向去搜,不到黄河不回头,直到遇到绝境了,搜不下去了,再换方向(换方向的过程就涉及到了回溯)。

        相比较而言,广搜的搜索方式就适合于解决两个点之间的最短路径问题。

bfs的搜索过程        

        这里利用队列的方式对bfs算法的搜索过程进行介绍,一开始先将起始节点入队,利用队列先进先出的特点在起始节点出队时将与起始节点相连的其他节点以此入队,然后继续重复上述的过程,再将队首元素弹出,将与之相邻的未访问过的节点依次添加入队,循环直到遇到目标节点或队列为空。

bfs的算法实现

        在代码随想录(新更新篇)中有介绍过bfs苏娜发的C++实现,这里就直接引用了。

int dir[4][2] = {0, 1, 1, 0, -1, 0, 0, -1}; // 表示四个方向
// grid 是地图,也就是一个二维数组
// visited标记访问过的节点,不要重复访问
// x,y 表示开始搜索节点的下标
void bfs(vector<vector<char>>& grid, vector<vector<bool>>& visited, int x, int y) {
    queue<pair<int, int>> que; // 定义队列
    que.push({x, y}); // 起始节点加入队列
    visited[x][y] = true; // 只要加入队列,立刻标记为访问过的节点
    while(!que.empty()) { // 开始遍历队列里的元素
        pair<int ,int> cur = que.front(); que.pop(); // 从队列取元素
        int curx = cur.first;
        int cury = cur.second; // 当前节点坐标
        for (int i = 0; i < 4; i++) { // 开始想当前节点的四个方向左右上下去遍历
            int nextx = curx + dir[i][0];
            int nexty = cury + dir[i][1]; // 获取周边四个方向的坐标
            if (nextx < 0 || nextx >= grid.size() || nexty < 0 || nexty >= grid[0].size()) continue;  // 坐标越界了,直接跳过
            if (!visited[nextx][nexty]) { // 如果节点没被访问过
                que.push({nextx, nexty});  // 队列添加该节点为下一轮要遍历的节点
                visited[nextx][nexty] = true; // 只要加入队列立刻标记,避免重复访问
            }
        }
    }

}

        bfs向各个方向搜索的可能性都相同,如果各边的权重都为1,那么使用BFS算法进行搜索就是最优的。但是在大多数情况下,往往各个方向的运动都会有不同的代价值(权重),如何对这些具有不同权重的图进行处理就就要引出下面的算法了。

2、迪杰斯特拉算法(Dijkstra)

核心思想

        与BFS直接将队列中弹出元素相连的所有元素都存入队列,Dijkstra利用贪心的思想每次选择都是累计代价值最小的节点进行相加。

        具体来说,Dijkstra创建了一个先变量g(n),以此来代替从起始节点到达当前节点所消耗的代价值,每次从开放集openset中寻找累计大价值最小的节点进行相加,而不是访问队列中的第一个元素。

优先级队列

        优先级队列中每一个元素都有着与之对应的优先级。在优先级队列中,优先级高的元素会比优先级低的元素先访问。

Dijkstra搜索过程

        输入:一个图表(包含节点和路径的集合)和一个起始节点;

        输出:到任意节点的最短路径。

        用伪代码进行简洁描述:        

Algorithm Dijkstra(G, start):
    let open_list be pirority queue
    open_list.push(start, 0)
    g[start] := 0

    while (open_list is not empty):
        current := open_list.pop()
        mark current as visited
        if current is the goal:
            return current
        for all unvisited neighbours next of current in Graph G:
            next_code := g[current] + cost(current, next)
            if next is not in open_list:
                open_list.push(next, next_cost)
            else:
                if g[next] > next_cost:
                    g[next] := next_cost

        先创建一个优先级队列open_list,将起始节点存入优先级队列,并设置累计代价函数的初值为0,然后进行循环(循环终止条件设为优先级队列非空),在循环中每次弹出优先级队列中的节点就要判断是否是目标节点,如果是目标节点就直接返回,若不是就要将弹出节点设为已访问节点,并对图表中当前弹出节点周围的其余邻居节点进行判断,若是未访问节点则直接存入优先级队列,若已访问则进行累计代价函数更新。

Dijkstra优缺点分析

        优点:

  • Dijkstra算法可以寻找到起始节点到图表上其他所有节点的最短路径;
  • Dijkstra孙发满足最优原则。

        缺点:

  • 该算法始终在优先级队列中寻找最短路径,而不考虑方向或距离目标的远近。因此,若使用它来搜索一个特定目标的最短路径时,并不高效。

3、A*算法

核心思想

        A*算法在Dijkstra算法的基础上引入启发式函数作为对目标节点的引导,从而提高了搜索的效率。

        启发式函数h(n)表示从节点n到目标的估计代价。使用f-score来评估每个节点的代价:f(n) = g(n) + h(n),然后在优先级队列中选取f-score最小的节点,而不是Dijkstra中的g-score。

A*搜索过程        
Algorithm Astar(G, start):
    let open_list be priority queue
    g[start] := 0
    f[start] = g[start] + h[start]
    open_list.push(start, f[start])
    
    while (open_list is not empty):
        current := open_list.pop()
        mark current as visited
        if current is the goal:
            return current
        for all unvisited neighbours next of current in Graph G:
            next_cost := g[current] + cost(current, next)
            if next is not in open_list:
                open_list.push(next, next_cost + h[next]
            else:
                if g[next] > next_cost
                    g[next] = next_cost
                    f[next] = next_cost + h[next]

        依然是创建一个优先级队列,并对g(n)和f(n)赋初值(假设启发式函数h(n))已知,再将初始节点和其对应的f-socre存入优先级队列,然后开始进入循环(循环的终止条件式队列非空),弹出队列中的节点,将其标志为已访问,若该节点为目标节点直接返回,否则要对其在图表中的邻居节点进行判断,若邻居节点未被访问则存入优先级队列中,存放时对应的代价函数还要加上h-score,若已访问则进行代价值更新。

启发式函数

        A*算法有别于Dijkstra的最大之处就在于启发算法的加入,但是在路径搜索问题中没有特定的启发式函数,因为每一种情况都是不同的。

        要注意启发式函数不能过高的估计代价值,只要启发式函数提供的估计值小于真实值,那么A*总会找到一条最优的路径并且通常比Dijkstra效率高

        如果启发式函数的代价值估计过高了,会产生什么影响呢,以下图为例:

         图中所示的B节点对应的启发式函数估计的代价值高于其真实值,因此C节点的f-score高于B节点的f-score,因此会错误地优先选择C节点通过,但实际上B节点才是更优的选择。

        A*搜索的效率与精度也取决于启发式函数的选择,主要有以下四种情况:

  • h(n) = 0:此时f-socre = g-score A*算法退化为Dijkstra算法;
  • h(n) < cost(n, goal):A*满足最优性,搜索效率上高于Dijkstra算法;
  • h(n) = cost(n, goal):A*满足最优性,并且达到最高搜索效率;
  • h(n) > cost(n, goal):启发式函数高估了实际代价,不具有最优性。

总结

  • BFS在各个方向上的搜索可能性相同,并且如果各边权重为1,bfs搜索得到的路径满足最优性;
  • Dijkstra算法利用贪心的思想选择累计代价值最低的节点,并且能够在有权图中表现出最优性,如果各边权重为1,那么Dijkstra搜索得到的路径和BFS搜索得到的相同。
  • A*是Dijkstra的改进,通过加入启发式函数提高搜索的效率,启发式函数的设计会直接影响到搜索的效率和精度。

动态规划

        基于搜索的路径规划问题除了上面的图搜索方法外,动态规划也是比较常用的方法。

        关于动态规划的理论和例子我在前面的代码随想录算法训练营Day38|动态规划理论基础中有过详细介绍,该节就仅仅介绍动态规划的适用场景。

  • 最优子结构

        我们可以把一个较大的问题分解成相似的子问题,如果我们能最优地解决子问题,我们就可以用它们来解决原来较大的问题;

  • 重叠子问题

        问题的递归解包含了许多重复多次的子问题。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

微服务day03-Nacos配置管理与Nacos集群搭建

一.Nacos配置管理 Nacos不仅可以作为注册中心&#xff0c;可以进行配置管理 1.1 统一配置管理 统一配置管理可以实现配置的热更新&#xff08;即不用重启当服务发生变更时也可以直接更新&#xff09; dataId格式&#xff1a;服务名-环境名.yaml&#xff0c;分组一般使用默认…

【比较mybatis、lazy、sqltoy、mybatis-flex操作数据】操作批量新增、分页查询(二)

orm框架使用性能比较 环境&#xff1a; idea jdk17 spring boot 3.0.7 mysql 8.0比较mybatis、lazy、sqltoy、mybatis-flex操作数据 测试条件常规对象 orm 框架是否支持xml是否支持 Lambda对比版本mybatis☑️☑️3.5.4sqltoy☑️☑️5.2.98lazy✖️☑️1.2.4-JDK17-SNAPS…

2024最新算法:鹦鹉优化算法(Parrot optimizer,PO)求解23个基准函数(提供MATLAB代码)

一、鹦鹉优化算法 鹦鹉优化算法&#xff08;Parrot optimizer&#xff0c;PO&#xff09;由Junbo Lian等人于2024年提出的一种高效的元启发式算法&#xff0c;该算法从驯养的鹦鹉中观察到的觅食、停留、交流和对陌生人行为的恐惧中汲取灵感。这些行为被封装在四个不同的公式中…

leetcode:37.解数独

题目理解&#xff1a;本题中棋盘的每一个位置都要放一个数字&#xff08;而N皇后是一行只放一个皇后&#xff09;&#xff0c;并检查数字是否合法&#xff0c;解数独的树形结构要比N皇后更宽更深。 代码实现&#xff1a;

2024免费mac苹果电脑的清理和维护软件CleanMyMac X

对于 Mac 用户来说&#xff0c;电脑的清理和维护是一件让人头疼的事情。但是&#xff0c;有了 CleanMyMac X&#xff0c;这一切都将变得轻松愉快。CleanMyMac X 是一款专为 Mac 设计的电脑清理软件&#xff0c;它以其强大的功能和简单的操作&#xff0c;让无数用户为之倾倒。 C…

数据结构开篇

目录 一. 如何学好数据结构二. 基本概念和术语2.1 区分数据、数据元素、数据项、数据对象2.2 数据结构2.2.1 逻辑结构2.2.2 存储结构 2.3 数据类型和抽象数据类型2.4 抽象数据类型的实现 \quad 一. 如何学好数据结构 勤于思考;多做练习;多上机;善于寻求帮助;不怕困难&#xff…

vue+element模仿实现云码自动验证码识别平台官网

一、项目介绍 项目使用传统vue项目结构实现&#xff0c;前端采用element实现。 element官网&#xff1a;Element - The worlds most popular Vue UI framework 云码官网地址&#xff1a;云码-自动验证码识别平台_验证码识别API接口_免费验证码软件 项目截图&#xff0c;支持…

浅析 explicit 关键字

浅析 explicit 关键字 文章目录 浅析 explicit 关键字前言案例剖析补充案例总结 前言 ​ C 提供了多种方式来实现类型转换和构造对象&#xff0c;然而&#xff0c;有时候这些方式会导致一些意想不到的结果&#xff0c;比如隐式转换和复制初始化。为了避免这些潜在的问题&#…

Redis安全加固策略:配置文件权限设置 配置本地日志存储目录 连接超时时间限制

Redis安全加固策略&#xff1a;配置文件权限设置 & 配置本地日志存储目录 & 连接超时时间限制 1.1 配置文件权限设置1.2 配置本地日志存储目录1.3 连接超时时间限制 &#x1f496;The Begin&#x1f496;点点关注&#xff0c;收藏不迷路&#x1f496; 1.1 配置文件权限…

【双指针】合并两个有序数组O(N)

合并两个有序数组 链接 . - 力扣&#xff08;LeetCode&#xff09;. - 备战技术面试&#xff1f;力扣提供海量技术面试资源&#xff0c;帮助你高效提升编程技能,轻松拿下世界 IT 名企 Dream Offer。https://leetcode.cn/problems/merge-sorted-array/ 题目 题解 采用双指针…

Java项目:31 基于SSM的勤工俭学管理系统

作者主页&#xff1a;源码空间codegym 简介&#xff1a;Java领域优质创作者、Java项目、学习资料、技术互助 文中获取源码 项目介绍 勤工助学系统有管理员&#xff0c;部门管理员&#xff0c;用户三个角色。 管理员功能有个人中心。管理员管理&#xff0c;部门管理员管理&…

vs code更新后json文件无法识别通配符 ,编译多文件失败的解决办法

问题描述 在Mac或者LInux上&#xff0c;进行C/C相同路径下进行多文件编译时&#xff0c;之前设置好的json文件突然不能解释通配符&#xff0c;并且将带有单引号的地址传给clang&#xff0c;由于*.c被扩在单引号中&#xff0c;clang找不到文件导致失败。 如果将命令端中的指令复…

新一代电话机器人开源PHP源代码

使用easyswoole 框架开发的 新一代电话机器人开源PHP源码 项目地址&#xff1a;https://gitee.com/ddrjcode/robotphp 代理商页面演示地址 http://119.23.229.15:8080 用户名&#xff1a;c0508 密码&#xff1a;123456 包含 AI外呼管理&#xff0c;话术管理&#xff0c;CR…

Android java基础_异常

一.异常的概念 在Java中&#xff0c;异常&#xff08;Exception&#xff09;是指程序执行过程中可能出现的不正常情况或错误。它是一个事件&#xff0c;它会干扰程序的正常执行流程&#xff0c;并可能导致程序出现错误或崩溃。 异常在Java中是以对象的形式表示的&#xff0c;…

力扣hot100题解(python版48-50题)

48、路径总和III 给定一个二叉树的根节点 root &#xff0c;和一个整数 targetSum &#xff0c;求该二叉树里节点值之和等于 targetSum 的 路径 的数目。 路径 不需要从根节点开始&#xff0c;也不需要在叶子节点结束&#xff0c;但是路径方向必须是向下的&#xff08;只能从…

香港服务器选择指南(挑选香港服务器的几个标准)

​  随着全球化的加速和互联网的普及&#xff0c;跨境访问和外贸活动越来越频繁。在这个背景下&#xff0c;香港服务器作为一种国际化的基础设施&#xff0c;受到了广泛欢迎。本文将探讨企业在选择香港服务器时应关注的几个标准事项。 1.可靠性和正常运行时间 停机可能会给企…

Linux:kubernetes(k8s)node节点加入master主节点(3)

Linux&#xff1a;kubernetes&#xff08;k8s&#xff09;搭建mater节点&#xff08;kubeadm&#xff0c;kubectl&#xff0c;kubelet&#xff09;-CSDN博客https://blog.csdn.net/w14768855/article/details/136415575?spm1001.2014.3001.5502 我在上一章部署好了主节点&…

qsort使用

qsort 是用来排序的数据的库函数,底层使用的是快速排序的方式 排序方式有:选择,冒泡,插入,快速, 希尔...... 对于qsort这个库函数: void qsort(void* base,size_t num,size_t size,int (*compar)(const void*,const void*) 其中 void* base 是指针,指向的是待排序的数组的第…

棋牌室计时计费管理系统的灯控器连接教程

棋牌室计时计费管理系统的灯控器连接教程 一、前言 以下教程以 佳易王棋牌室计时计费管理系统软件V18.0为例说明 软件文件下载可以点击最下方官网卡片——软件下载——试用版软件下载 如上图&#xff0c;计时计费软件在开始计时的时候&#xff0c;点击 开始计时 如果连接了…

第19章-IPv6基础

1. IPv4的缺陷 2. IPv6的优势 3. 地址格式 3.1 格式 3.2 长度 4. 地址书写压缩 4.1 段内前导0压缩 4.2 全0段压缩 4.3 例子1 4.4 例子 5. 网段划分 5.1 前缀 5.2 接口标识符 5.3 前缀长度 5.4 地址规模分类 6. 地址分类 6.1 单播地址 6.2 组播地址 6.3 任播地址 6.4 例子 …