A*搜索算法

news2024/12/23 23:35:46

前言

这个我也不知道算不算是A*搜索算法,可能只是A搜索算法。

首先看相关的定义:

启发式搜索在搜索过程中根据启发信息评估各个节点的重要性,优先搜索重要的节点。

估价函数的任务就是估计待搜索节点“有希望”的程度。

估价函数f(n)定义为从初始节点经过节点n到达目的节点的路径的最小代价估计值,其中一般形式是

f(n)=g(n)+h(n)

g(n)是从初始节点到节点n的实际代价,而h(n)是从节点n到目的节点的最佳路径的估计价值。

在这篇博客中就把事件进行简化了,g(n)表示当前走过的步数,h(n)估计代价用曼哈顿距离来表示。

参考链接:

人工智能大作业——A*算法迷宫寻路问题_a*算法实现迷宫寻路功能-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/weixin_46037153/article/details/107136560A*搜索算法(A-Star Search)简介及保姆级代码解读 (qq.com)icon-default.png?t=N7T8https://mp.weixin.qq.com/s?__biz=MzU1NjEwMTY0Mw==&mid=2247554483&idx=1&sn=c3e6a3259f1b469eded07a5498790186&chksm=fbc86cd7ccbfe5c12f4dddf139f73cb5c2879044867bced71edb0243b155f3d68eda50d0db6a&scene=27机器人路径规划算法(十一)A-star算法 - Mronne's Blogicon-default.png?t=N7T8https://mronne.github.io/2020/04/03/%E6%9C%BA%E5%99%A8%E4%BA%BA%E8%B7%AF%E5%BE%84%E8%A7%84%E5%88%92%E7%AE%97%E6%B3%95-%E5%8D%81%E4%B8%80-A-star-%E7%AE%97%E6%B3%95.html

思路讲解

前期准备

用MAP二维数组来表示待搜索的地图,其中1表示道路受阻碍,0表示通路。

定义Grid来表示地图中的节点,其中x,y表示坐标,fn,hn,gn是之后需要用到的估计值。

定义两个集合来储存新加入的节点以及走过的节点,我这里用到的是链表,因为添加和删除元素比较多。

 //定义地图,直接利用二维数组来实现(0表示可以通过,1表示不能通过
    public static int[][] MAP={
            {0,1,0,0,0,0,0},
            {0,0,1,0,0,0,0},
            {1,0,0,1,0,0,0},
            {0,1,0,1,1,1,1},
            {0,0,0,0,0,0,0},
            {0,0,0,0,0,0,0},
            {0,0,0,1,1,1,0},
    };

    //把方格抽象成一个类
    public static class Grid{
        private int x;//横坐标
        private int y;//纵坐标
        //fn=hn+gn
        private int fn;//估计函数
        private int hn;//估计代价
        private int gn;//实际代价

        private Grid parent;//父节点

        //构造方法
        public Grid(int x,int y){
            this.x=x;
            this.y=y;
        }


        //实例化一个方格节点
        public void initGrid(Grid parent,Grid end){
            this.parent=parent;

            //计算gn
            if(parent!=null){
                //实际的代价加一相当于前进了一步
                this.gn=parent.gn+1;
            }else {
                this.gn=1;
            }

            //计算hn的大小(这里用的估计代价是曼哈顿距离
            this.hn=Math.abs(this.x-end.x)+Math.abs(this.y-this.y);

            //计算fn的大小
            this.fn=this.gn+this.hn;
        }
    }

    //准备两个链表来储存需要选择的节点以及已经走过的节点
    public static LinkedList<Grid> selectList=new LinkedList<Grid>();
    public static LinkedList<Grid> walkList=new LinkedList<Grid>();

查找最小估价值的节点

 方法的作用是返回selectList集合中的fn最小的节点。(fn表示最小代价估计值)

 //返回最小的那个节点
    private static Grid findMinGrid(LinkedList<Grid>selectList){

        Grid tmpgrid=selectList.get(0);
        for(Grid grid:selectList){
            //更新最小节点
            if(grid.fn<tmpgrid.fn){
                tmpgrid=grid;
            }
        }
        return tmpgrid;
    }

判断当前节点是否已经添加

 判断(x,y)坐标是否在grids集合中,如果相等,表示已经添加到集合中了。

 //判断当前的节点是否已经添加
    private static boolean contains(LinkedList<Grid>grids,int x,int y){
        for (Grid grid:grids){
            //坐标在grids集合中有就是已经被添加了
            if((grid.x==x)&&(grid.y==y)){
                return true;
            }
        }
        return false;
    }

 判断当前的节点是否合法

判断当前节点的坐标是否越界,以及节点是否已经被添加到集合中了,如果已经被添加了就不用管了。

//判断当前节点是否合法
    private static boolean legitimacy(int x,int y,LinkedList<Grid>selectList,LinkedList<Grid>walkList) {
        //判断坐标是否越界
        if (x < 0 || x >= MAP.length || y < 0 || y >= MAP[0].length) {
            return false;
        }
        //判断当前节点是否是障碍
        if (MAP[x][y] == 1) {
            return false;
        }
        //判断当前节点是否被添加
        if (contains(selectList, x, y)) {
            return false;
        }
        //判断当前节点是否已经走过了
        if (contains(walkList, x, y)) {
            return false;
        }
        //所以条件都满足,他就是合法的
        return true;
    }

 添加相邻的节点

他的思路就是先找出目前fn最小的那个节点,然后对那个节点相邻的节点进行判断,如果相邻的节点是合法的,就把节点添加到集合中。

//把所有符合要求的相邻节点都放置到list集合里面里面
    private static LinkedList<Grid>findNeighbors(Grid grid, LinkedList<Grid>selectList,LinkedList<Grid>walkList){
        LinkedList<Grid>list=new LinkedList<Grid>();
        //判断相邻节点的合法性
        if(legitimacy(grid.x,grid.y-1,selectList,walkList)){//下(用数组来看的话他就是往上)
            list.add(new Grid(grid.x,grid.y-1));
        }
        if(legitimacy(grid.x,grid.y+1,selectList,walkList)){//上
            list.add(new Grid(grid.x,grid.y+1));
        }
        if(legitimacy(grid.x-1,grid.y,selectList,walkList)){//左
            list.add(new Grid(grid.x-1,grid.y));
        }
        if(legitimacy(grid.x+1,grid.y,selectList,walkList)){//右
            list.add(new Grid(grid.x+1,grid.y));
        }
        return list;
    }

 算法实现

先把start节点最开始添加到集合中,然后不断的扩展他,知道集合中没有节点,或者找到终点节点表示结束。

//A*算法的实现(需要开始位置和结束位置
    private static void algorithmImplementation(Grid start,Grid end){

        //将起点加入链表之后开始寻路
        selectList.add(start);

        //链表不为空(没有最后没有到达终点也会停止)
        while(selectList.size()>0){
            //找到在需要选择的节点中最小的那个节点,之后需要用它进行扩展
            Grid nowGrid=findMinGrid(selectList);

            //从中删除最小的那个节点
            selectList.remove(nowGrid);
            //将这个节点添加到已经走过的路径中
            walkList.add(nowGrid);

            //寻找他的相邻节点,把合法的节点都添加进来
            LinkedList<Grid>neighbors=findNeighbors(nowGrid,selectList,walkList);

            for(Grid grid:neighbors){
                //判断集合中是否添加了grid节点
                if(!selectList.contains(grid)){
                    //进行初始化
                    grid.initGrid(nowGrid,end);
                    selectList.add(grid);
                }
            }
            //判断是否可以结束
            for(Grid grid:selectList){
                if((grid.x==end.x)&&(grid.y==end.y)){
                    walkList.add(end);
                    return;
                }
            }
        }
    }

 主方法

对储存的节点进行打印,走过的道路用2来表示。

  //主方法
    public static void main(String[] args) {
        System.out.println("原始地图是:");
        for (int i = 0; i < MAP.length; i++) {
            for (int j = 0; j < MAP[0].length; j++) {
                System.out.print(MAP[i][j]+"\t");
            }
            System.out.println();
        }

        Grid grid1=new Grid(0,0);
        Grid grid2=new Grid(MAP.length-1,MAP[0].length-1);
        algorithmImplementation(grid1,grid2);
        //走过的路径用2表示
        for(Grid grid:walkList){
            MAP[grid.x][grid.y]=2;
        }
        System.out.println("搜索后的地图是:");
        for (int i = 0; i < MAP.length; i++) {
            for (int j = 0; j < MAP[0].length; j++) {
                System.out.print(MAP[i][j]+"\t");
            }
            System.out.println();
        }
    }

Java

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

public class AStarSearch {
    //定义地图,直接利用二维数组来实现(0表示可以通过,1表示不能通过
    public static int[][] MAP={
            {0,1,0,0,0,0,0},
            {0,0,1,0,0,0,0},
            {1,0,0,1,0,0,0},
            {0,1,0,1,1,1,1},
            {0,0,0,1,0,0,0},
            {0,1,0,0,0,0,0},
            {0,0,0,1,1,1,0},
    };

    //把方格抽象成一个类
    public static class Grid{
        private int x;//横坐标
        private int y;//纵坐标
        //fn=hn+gn
        private int fn;//估计函数
        private int hn;//估计代价
        private int gn;//实际代价

        private Grid parent;//父节点

        //构造方法
        public Grid(int x,int y){
            this.x=x;
            this.y=y;
        }


        //实例化一个方格节点
        public void initGrid(Grid parent,Grid end){
            this.parent=parent;

            //计算gn
            if(parent!=null){
                //实际的代价加一相当于前进了一步
                this.gn=parent.gn+1;
            }else {
                this.gn=1;
            }

            //计算hn的大小(这里用的估计代价是曼哈顿距离
            this.hn=Math.abs(this.x-end.x)+Math.abs(this.y-this.y);

            //计算fn的大小
            this.fn=this.gn+this.hn;
        }
    }

    //准备两个链表来储存需要选择的节点以及已经走过的节点
    public static LinkedList<Grid> selectList=new LinkedList<Grid>();
    public static LinkedList<Grid> walkList=new LinkedList<Grid>();

    //A*算法的实现(需要开始位置和结束位置
    private static void algorithmImplementation(Grid start,Grid end){

        //将起点加入链表之后开始寻路
        selectList.add(start);

        //链表不为空(没有最后没有到达终点也会停止)
        while(selectList.size()>0){
            //找到在需要选择的节点中最小的那个节点,之后需要用它进行扩展
            Grid nowGrid=findMinGrid(selectList);

            //从中删除最小的那个节点
            selectList.remove(nowGrid);
            //将这个节点添加到已经走过的路径中
            walkList.add(nowGrid);

            //寻找他的相邻节点,把合法的节点都添加进来
            LinkedList<Grid>neighbors=findNeighbors(nowGrid,selectList,walkList);

            for(Grid grid:neighbors){
                //判断集合中是否添加了grid节点
                if(!selectList.contains(grid)){
                    //进行初始化
                    grid.initGrid(nowGrid,end);
                    selectList.add(grid);
                }
            }
            //判断是否可以结束
            for(Grid grid:selectList){
                if((grid.x==end.x)&&(grid.y==end.y)){
                    walkList.add(end);
                    return;
                }
            }
        }
    }
    //把所有符合要求的相邻节点都放置到list集合里面里面
    private static LinkedList<Grid>findNeighbors(Grid grid, LinkedList<Grid>selectList,LinkedList<Grid>walkList){
        LinkedList<Grid>list=new LinkedList<Grid>();
        //判断相邻节点的合法性
        if(legitimacy(grid.x,grid.y-1,selectList,walkList)){//下(用数组来看的话他就是往上)
            list.add(new Grid(grid.x,grid.y-1));
        }
        if(legitimacy(grid.x,grid.y+1,selectList,walkList)){//上
            list.add(new Grid(grid.x,grid.y+1));
        }
        if(legitimacy(grid.x-1,grid.y,selectList,walkList)){//左
            list.add(new Grid(grid.x-1,grid.y));
        }
        if(legitimacy(grid.x+1,grid.y,selectList,walkList)){//右
            list.add(new Grid(grid.x+1,grid.y));
        }
        return list;
    }
    //判断当前节点是否合法
    private static boolean legitimacy(int x,int y,LinkedList<Grid>selectList,LinkedList<Grid>walkList) {
        //判断坐标是否越界
        if (x < 0 || x >= MAP.length || y < 0 || y >= MAP[0].length) {
            return false;
        }
        //判断当前节点是否是障碍
        if (MAP[x][y] == 1) {
            return false;
        }
        //判断当前节点是否被添加
        if (contains(selectList, x, y)) {
            return false;
        }
        //判断当前节点是否已经走过了
        if (contains(walkList, x, y)) {
            return false;
        }
        //所以条件都满足,他就是合法的
        return true;
    }
    //判断当前的节点是否已经添加
    private static boolean contains(LinkedList<Grid>grids,int x,int y){
        for (Grid grid:grids){
            //坐标在grids集合中有就是已经被添加了
            if((grid.x==x)&&(grid.y==y)){
                return true;
            }
        }
        return false;
    }
    //返回最小的那个节点
    private static Grid findMinGrid(LinkedList<Grid>selectList){

        Grid tmpgrid=selectList.get(0);
        for(Grid grid:selectList){
            //更新最小节点
            if(grid.fn<tmpgrid.fn){
                tmpgrid=grid;
            }
        }
        return tmpgrid;
    }

    //主方法
    public static void main(String[] args) {
        System.out.println("原始地图是:");
        for (int i = 0; i < MAP.length; i++) {
            for (int j = 0; j < MAP[0].length; j++) {
                System.out.print(MAP[i][j]+"\t");
            }
            System.out.println();
        }

        Grid grid1=new Grid(0,0);
        Grid grid2=new Grid(MAP.length-1,MAP[0].length-1);
        algorithmImplementation(grid1,grid2);
        //走过的路径用2表示
        for(Grid grid:walkList){
            MAP[grid.x][grid.y]=2;
        }
        System.out.println("搜索后的地图是:");
        for (int i = 0; i < MAP.length; i++) {
            for (int j = 0; j < MAP[0].length; j++) {
                System.out.print(MAP[i][j]+"\t");
            }
            System.out.println();
        }
    }
}

总结

现在只写了Java的代码,之后会有时间会用其他语言写,之前问了老师,他说用Python可以实现图形化的那种,但是面前还不太会,以后有时间就会更新一下这篇博客。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

vue 实现数字验证码功能

需求&#xff1a;写了一个 手机发送验证码后 输入固定验证码的功能 封装成一个组件,如下: <template><div class"conts"><div class"box"><div class"code_list"><div :class"[ code_item, hideIndex 0 ? co…

Ubuntu Qt 5.15.2 支持 aarch64

概述 AArch64是ARMv8 架构的一种执行状态。 为了更广泛地向企业领域推进&#xff0c;需要引入64 位构架。 同时也需要在ARMv8 架构中引入新的AArch64 执行状态。 AArch64 不是一个单纯的32 位ARM 构架扩展&#xff0c;而是ARMv8 内全新的构架&#xff0c;完全使用全新的A64 指令…

软件设计模式——外观模式

摘要 本文主要分析设计模式 - 结构型 - 外观(Facade)&#xff0c;它提供了一个统一的接口&#xff0c;用来访问子系统中的一群接口&#xff0c;从而让子系统更容易使用。 一、外观模式的意图 提供了一个统一的接口&#xff0c;用来访问子系统中的一群接口&#xff0c;从而让…

2023蓝帽杯半决赛取证复现

1.检材数据开始提取是今年什么时候&#xff1f;&#xff08;答案格式&#xff1a;04-12 13:26&#xff09; 09-11 17:21 这题做错了 其实当时盘古石手机取证里面就有的&#xff0c;想多了去看了日志文件 是真的有点歧义&#xff0c;20分就开始提取任务了 2.嫌疑人手机SD卡存…

TLS/SSL(七) 非对称密码应用 之DH密钥交换协议

一 DH密钥交换协议 DH密钥交换协议用来沟通协商出后面AES算法的密钥,是广泛使用、安全的密钥交换协议 ① RSA密钥交换 备注&#xff1a; RSA算法没有前向保密性&#xff0c;所以TLS1.3及以后的协议禁止RSA作为密钥协商算法 如何理解前向保密性 故事&#xff1a; 斯诺登事…

Spring Cloud Alibaba Seata 搭建以及分布式事务的验证

文章目录 Spring Cloud Alibaba Seata 搭建以及分布式事务的验证1.seata 简介2. seata的三大角色3. Seata的流程4. Seata AT模式5. Seata搭建找到模板案例&#xff0c;照着抄6. Seata Client快速开始6.1 声明式事务实现&#xff08;GlobalTransactional&#xff09;6.2 添加依赖…

【牛客网】倒置字符串

思路 首先将整个字符串逆序,再分别将每个单词逆序 代码 import java.util.Scanner;// 注意类名必须为 Main, 不要有任何 package xxx 信息 public class Main {public static void reverse(int begin, int end, char[] array){while(begin < end){char temp array[begin…

第十四届蓝桥杯大赛软件赛决赛 C/C++ 大学 B 组 试题 A: 子 2023

[蓝桥杯 2023 国 B] 子 2023 试题 A: 子 2023 【问题描述】 小蓝在黑板上连续写下从 1 1 1 到 2023 2023 2023 之间所有的整数&#xff0c;得到了一个数字序列&#xff1a; S 12345678910111213 ⋯ 20222023 S 12345678910111213\cdots 20222023 S12345678910111213⋯2…

USB到UART桥接控制器——GP232RNL

GP232RNL是一款高度集成的USB到UART桥接控制器&#xff0c;提供了一种简单的解决方案&#xff0c;可以使用最少的元器件和PCB空间&#xff0c;将RS232接口转换为USB接口。GP232RNL包括一个USB 2.0全速功能控制器、USB收发器、振荡器、EEPROM和带有完整的调制解调器控制信号的异…

Python完整教程

Python由荷兰国家数学与计算机科学研究中心的吉多范罗苏姆于1990年代初设计&#xff0c;作为一门叫作ABC语言的替代品。 [1] Python提供了高效的高级数据结构&#xff0c;还能简单有效地面向对象编程。Python语法和动态类型&#xff0c;以及解释型语言的本质&#xff0c;使它成…

【Hash表】无重复字符的最长字串-力扣 3 题

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kuan 的首页,持续学…

中国TO B投资,迈入第二周期

2023年,中国TOB正在愈发成熟,迈进第二个周期的趋势已经体现在融资金额上。 作者|斗斗 编辑|皮爷 出品|产业家 TOB&#xff0c;依旧是一级市场的大热门。 统计数据显示&#xff0c;截止2023年8月31日&#xff0c;TOB领域共发生融资事件406起&#xff0c;同比2022年减少…

人工智能核心基础 - 规划和概要

Hi&#xff0c;你好。又见面咯&#xff0c;我是茶桁。 在之前&#xff0c;我花了两个来月的时间撰写了「Python篇」和「数学篇」&#xff0c;希望小伙伴们在正式进入AI之前能够打好一个基础。那么今天开始&#xff0c;我们将正式开始AI基础的学习。 这一节课咱们先不着急直接…

细胞机器人系统中的群体智能

摘要 细胞机器人系统具有“智能”行为能力。本文分析了这种智能的含义。本文根据上述不可思议智能行为的不可预测性来定义机器人智能和机器人系统智能。对不可预测性概念的分析与&#xff08;1&#xff09;统计不可预测、&#xff08;2&#xff09;不可访问、&#xff08;3&am…

STL中string类的实现

目录 引入 构造 | 析构函数 构造函数 析构函数 返回指针的c_str() 求字符大小的size() operator[] 普通对象调用&#xff1a; const对象调用&#xff1a; 迭代器的实现 范围for 深浅拷贝 浅拷贝的不足 实现深拷贝 赋值的深拷贝 传统写法与现代写法 传统写法 现…

前端开发之服务器的基本概念与初识Ajax

1&#xff0c;服务器的基本概念与初识Ajax 1.1 URL地址的组成部分 1.2 客户端与服务器的通信过程 1.3 网页中如何请求数据 1.4 $.get()函数 1.4.1 $.get()函数的语法 // jQuery 中 $.get() 函数的功能单一&#xff0c;专门用来发起 get 请求&#xff0c;从而将服务器上的资源…

Cartesi Rollups在主网上正式启用,推出首个DApp,名为Honeypot

Cartesi的贡献者呼吁所有Web3开发者测试并加固Cartesi Rollups的安全性&#xff0c;因为Honeypot的资金每周以复利增长8% 2023年9月26日&#xff0c;在今天的美国纽约&#xff0c;Cartesi&#xff08;CTSI&#xff09;, 一种具有能够运行Linux发行版的虚拟机的特定应用程序的R…

​cannot import name ‘container_abcs’ from ‘torch._six’​

因为1.8版本之后container_abcs就已经被移除了。 cannot import name ‘container_abcs’ from ‘torch._six’ 解决办法: 改成以下写法&#xff1a; import collections.abc as container_abcs int_classes int

怎么写一个可以拖拽缩放的div?

说在前面 元素拖拽和缩放现在也是一个很常见的功能&#xff0c;让我们从实现div元素的拖拽缩放开始来了解元素拖拽缩放的具体原理和实现方法吧。 效果展示 实现步骤 画一个div 首先我们需要先画一个div&#xff0c;并给它8个方位&#xff08;上、下、左、右、左上、右上、右下…

Linux学习之HIS部署(5)

MySQL部署 #安装MySQL服务 [rootServices ~]# yum clean all; yum repolist -v ... Total packages: 8,265 [rootServices ~]# yum -y install mysql.x86_64 mysql-server.x86_64 mysql-devel.x86_64 ... Complete! [rootServices ~]# #启动MySQL服务 [rootServices ~]# syst…