寻路(A*算法)

本文介绍了一种基于A*算法的寻路方法,通过Java实现了在图片中寻找两点间最短路径的功能。该实现包括GUI界面展示、A*算法核心逻辑及节点类定义。程序读取图片,识别起点与终点并进行寻路,最后在界面上显示路径。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在一张图片中寻找起点与终点的最短路径,图片是bmp格式

代码分为三个类,一个是GUI界面,另一个是核心的A*算法,还有一个是定义的'点'的类

GUI界面

import java.io.*;
import java.awt.*;
import javax.swing.*;
import java.util.*;
import java.awt.event.*;
import javax.swing.event.*;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
public class MainFram extends JFrame implements ActionListener
{
	//现在面板上把图片画出来,然后给按钮添加空间,发生点击时间时重绘图片,算法写在重绘的方法里
	JLabel l1;
	JButton b1,b2,b;
	JPanel panBasic,pan1,pan2;
	BufferedImage img;
	String str="E:\\Editplus\\寻路图片\\1.bmp";
	int i=1;
	AStar load;
	//zhijingxunlu load;
	MainFram(){
		setTitle("寻路算法");
		l1=new JLabel("图片1");
		b1=new JButton("<<");
		b2=new JButton(">>");
		b=new JButton("开始寻路");                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   
		setLayout(null);
		this.setSize(650,400);
		this.setLocation(200,200);
		panBasic=new Mypanel();
		l1.setBounds(270,10,50,30);
		panBasic.setBounds(150,50,330,230);
		b1.setBounds(180,290,50,30);
		b2.setBounds(260,290,50,30);
		b.setBounds(350,290,100,30);
		this.add(l1);
		this.add(panBasic);
		this.add(b1);
		this.add(b2);
		this.add(b);
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		this.setVisible(true);
		b1.addActionListener(this);
		b2.addActionListener(this);
		b.addActionListener(this);
	}
	public static void main(String[] args) 
	{
		new MainFram();
	}
	public void paint(){//绘制寻路图片的方法
		Graphics g=panBasic.getGraphics();//获得当前界面上的值,后面改变图片都是重绘pan1,只有pan1由Graphics
		load=new AStar();
		//load=new zhijingxunlu();//Point
		load.setImage(img);
		g.setColor(Color.red);
		g.drawString("起点",load.getsNode().getX(), load.getsNode().getY());
		g.fillRect(load.getsNode().getX(), load.getsNode().getY(), 3, 3);
		g.fillRect(load.geteNode().getX(), load.geteNode().getY(), 3, 3);
		g.drawString("终点", load.geteNode().getX()-25,load.geteNode().getY());
		System.out.println("起点:("+load.getsNode().getX()+","+load.getsNode().getY()+")");
		System.out.println("终点:("+load.geteNode().getX()+","+load.geteNode().getY()+")");
		
			load.search();//寻路算法Node
		
		for(int i=0;i<load.resultList.size();i++){
			g.fillRect(load.resultList.get(i).getX(),load.resultList.get(i).getY(),1,1);
		}
		System.out.println(load.resultList.size()+"个节点");
	}
	class Mypanel extends JPanel
{
	public void paint(Graphics g){
		super.paint(g);
		try{
			img=ImageIO.read(new File(str));
		}
		catch(IOException e){
			System.out.println(e.toString());
		}
		g.drawImage(img,0,0,null);
	}
}
	public void actionPerformed(ActionEvent e){
		if(e.getSource()==b1){
			if(i>1){
				--i; 
				str="E:\\Editplus\\寻路图片\\"+i+".bmp";
				pan1=new Mypanel();
				l1.setText("图片"+i);
				this.repaint();
			}
		}
		
		if(e.getSource()==b2){
			if(i<15){
				++i;
				str="E:\\Editplus\\寻路图片\\"+i+".bmp";
				pan2=new Mypanel();
				l1.setText("图片"+i);
				this.repaint();
			}
		}
		if(e.getSource()==b){
			paint();
		}
	}
}

像素点的类
class Node
{

	private int x;//节点在地图中的横坐标
	private int y;//节点在地图中的纵坐标
	private int g;//从起始点移动到此点的距离
	private int h;//到终点的曼哈顿距离
	private int f;//g+h,判断依据
	Node parNode;

	Node(int i, int j, Node node)
	{
		this.x = i;
		this.y = j;
		this.parNode = node;
	}

	public void setX(int i)
	{
		this.x = i;
	}

	public void setY(int i)
	{
		this.y = i;
	}

	public void setparNode(Node node)
	{
		this.parNode = node;
	}

	public int getX()
	{
		return this.x;
	}

	public int getY()
	{
		return this.y;
	}

	public Node getparNode()
	{
		return this.parNode;
	}

	public void setF(int i)
	{
		this.f = i;
	}

	public void setG(int i)
	{
		this.g = i;
	}

	public void setH(int i)
	{
		this.h = i;
	}

	public int getF()
	{
		return this.f;
	}

	public int getH()
	{
		return this.h;
	}

	public int getG()
	{
		return this.g;
	}
}

A*算法:A*算法用于找寻地图中两点之间的最短路径,详细讲解大家可以看这篇连接。点击打开链接(侵删)

import java.util.*;
import java.awt.List;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.awt.image.BufferedImage;
public class AStar {//输入图片     返回一个结果数组
	private int map_Width;// 得到图片的宽的
	private int map_Height;//得到图片的高度
	private Node sNode;  //创建初始点
	private Node eNode;	 //创建终结点
	private BufferedImage img=null; //传入的图片
	private final int cost_straight=10;//上下左右移动
	private final int cost_diagonal=14;//斜线上的移动
	private final int stepLength=1;//寻找下一个点时的步长
	private int map[][]; //地图
	ArrayList<Node> openList=new ArrayList(); //开启列表
	ArrayList<Node> closedList=new ArrayList(); //关闭列表
	ArrayList<Node> resultList=new ArrayList(); //结果列表
	AStar(){//构造函数
	}
	public void setImage(BufferedImage img){//传入图片
		this.img=img;
		this.map_Height=img.getHeight();
		this.map_Width=img.getWidth();
		initmap();
		setNodes();
		setNodee();
	}
	public void setNodes(){
		Node n;
		int x=2,y=0;
		for(int i=0;i<img.getHeight();i++){
			if(map[x][i]==1){
				y=i;
				break;
			}
		}
		n=new Node(x,y,null);
		this.sNode=n;
		System.out.println("起点的坐标是:("+x+","+y+")");
	}
	public void setNodee(){
		Node n;
		int x=img.getWidth()-2,y=0;
		for(int i=0;i<img.getHeight();i++){
			if(map[x][i]==1){
				y=i;
				break;
			}
		}
		n=new Node(x,y,null);
		this.eNode=n;
		System.out.println("终点的坐标是:("+x+","+y+")");
	} 
	public void initmap(){
		map=new int[map_Width+1][map_Height+1];
		for(int i=0;i<map_Width;i++){
			for(int j=0;j<map_Height;j++){
				//像素颜色由红,绿,蓝三色组成,三色的值[0-255]2进制下的8位  16进制下的2位 用移位的方法分别获得
				//三原色全部位0组成的就是黑色
				int RGB=img.getRGB(i, j);//获得图片的16进制像素值
				int R=(RGB&0xff0000)>>16;//获得16进制下的前两位,也就是2进制下的前8位
				int G=(RGB&0xff00)>>8;//位与代表取那几位
				int B=(RGB&0xff);
				if(R==0&&G==0&&B==0){
					map[i][j]=1;
				}
				else{
					map[i][j]=0;
				}
			}
		}
	}
	public void setsNode(Node n){
		this.sNode=n;
	}
	public void seteNode(Node n){
		this.eNode=n;
	}
	public Node getsNode(){
		return sNode;
	}
	public Node geteNode(){
		return eNode;
	}
	public void run(){
		search();
	}
	public void search(){
		if(sNode.getX()<0||sNode.getX()>map_Width
		 ||sNode.getY()<0||sNode.getY()>map_Height
		 ||eNode.getY()<0||eNode.getY()>map_Width
		 ||eNode.getY()<0||eNode.getY()>map_Height
		){//判断是否出界
			System.out.println("超出了图像范围!");
			return;
		}
		if(map[sNode.getX()][sNode.getY()]==0||map[eNode.getX()][eNode.getY()]==0){
			System.out.println("节点选择不正确!!!");
			return;
		}
		openList.add(sNode);//刚开始就将初始点添加到开启列表中
		long begintime=System.currentTimeMillis();
		resultList=search(sNode,eNode);//重载search方法,调用A*算法
		if(resultList.size()==0){
			System.out.println("没有找到路线");
			return;
		}
		long endtime=System.currentTimeMillis();
		System.out.println("寻路时间="+(endtime-begintime)+"ms");
		return;
	}
	public ArrayList<Node> search(Node sNode,Node eNode){
		//返回一个结果集
		boolean flag=false;
		Node node=null;//当前节点
		while(openList.size()>0){
			node=openList.get(0);//当前节点位上一下的F值最小的点
			if(node.getX()==eNode.getX()&&node.getY()==eNode.getY()){
				flag=true;//如果当前节点等于最终节点,那么跳出循环
				break;
			}
			//检查当前节点周围的所有节点
			//上
			if(node.getY()-1>0){
				checkPath(node.getX(),node.getY()-1,node,eNode,cost_straight);
			}
			//下
			if(node.getY()+1<map_Height){
				checkPath(node.getX(),node.getY()+1,node,eNode,cost_straight);
			}
			//左
			if(node.getX()-1>0){
				checkPath(node.getX()-1,node.getY(),node,eNode,cost_straight);
			}
			//右
			if(node.getX()+1<map_Width){
				checkPath(node.getX()+1,node.getY(),node,eNode,cost_straight);
			}//四个方向,八个方向更为精确,但是耗时较大
			//左下
			if(node.getX()-1>0&&node.getY()+1<map_Height){
				checkPath(node.getX()-1,node.getY()+1,node,eNode,cost_diagonal);
			}
			//右下
			if(node.getX()+1<map_Width&&node.getY()+1<map_Height){
				checkPath(node.getX()+1,node.getY()+1,node,eNode,cost_diagonal);
			}
			//左上
			if(node.getX()-1>0&&node.getY()-1>0){
				checkPath(node.getX()-1,node.getY()-1,node,eNode,cost_diagonal);
			}
			//右上
			if(node.getX()+1<map_Width&&node.getY()-1>0){
				checkPath(node.getX()+1,node.getY()-1,node,eNode,cost_diagonal);
			}
			closedList.add(openList.remove(0));
			Collections.sort(openList,new CompareNode());
		}
		if(flag){
			getPath(resultList, node);//由终点节点往前回溯找到结果集
		}
		return resultList;//结果集  路径所有的点都包含在其中
	}
	//如果没有处于开启列表中,那么添加到开启列表中,如果已经处于开启列表中,那么进行判断:
	//是经过上一个节点再到达此处G值小还是原本的G值小,H值不变,G值的大小决定了F的大小
	//如果经父节点的G值更小,那么更新此点的参数值,并将父节点指向上一个节点
		public void checkPath(int x,int y,Node parNode,Node eNode,int cost){
			Node node=new Node(x,y,parNode);
			if(map[x][y]==0){
				closedList.add(node);  
				return;//点在路外
			}
			if(isListContains(closedList, x, y)!=-1){
				return ;//说明点处于关闭列表中
			}
			int dex=-1;
			if((dex=isListContains(openList, x, y))!=-1){//说明在开启列表中
				  if(node.getparNode().getG()+cost<openList.get(dex).getG()){
					node.setparNode(parNode);//检测新的路线是否更好,如果是改变他的父节点
					CountG(node,cost);
					CountF(eNode);
				  }
			}
			else{//不在关闭列表中  且不在开启列表中 就添加进来
				node.setparNode(parNode);
				Count(node,eNode,cost);
				openList.add(node);
			}
		}
	public int isListContains(ArrayList<Node> list,int x,int y){//检测这个点是否在这种状态集中
		for(int i=0;i<list.size();i++){
			if(list.get(i).getX()==x&&list.get(i).getY()==y){
				return i;//返回i说明在这个集合中,并且索引值就是i
			}
		}
		return -1;//说明不在
	}
	//从终点回溯到起点
	public void getPath(ArrayList<Node> list,Node n){
		if(n.getparNode()!=null){
			getPath(list,n.getparNode());
		}
		list.add(n);
	}
	//重新更新节点的参数
	public void Count(Node n,Node eNode,int cost){
		CountF(n);
		CountG(n,cost);
		CountH(n,eNode);
	}
	public void CountF(Node n){
		n.setF(n.getG()+n.getH());
	}
	public void CountG(Node n,int cost){
		if(n.getparNode()==null){
			n.setG(cost);
		}
		else
		n.setG(n.getparNode().getG()+cost);
	}
	public void CountH(Node n,Node eNode){
		n.setH(Math.abs(eNode.getX()-n.getX())+Math.abs(eNode.getY()-n.getY()));
	}
	//按照F的大小进行排序
	class CompareNode implements Comparator<Node>{
		//集成了接口一下是接口中的抽象方法
		public int compare(Node o1, Node o2) {
			//o1-o2是按照升序排列
			return o1.getF()-o2.getF();
		}
		
	}
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值