A*(A-Star)算法是一种静态路网中求解最短路最有效的直接搜索方法。
注意是最有效的直接搜索算法。之后涌现了很多预处理算法(ALT,CH,HL等等),在线查询效率是A*算法的数千甚至上万倍。
公式表示为: f(n)=g(n)+h(n)
其中 f(n) 是从初始点经由节点n到目标点的估价函数,
g(n) 是在状态空间中从初始节点到n节点的实际代价,
h(n) 是从n到目标节点最佳路径的估计代价。
保证找到最短路径(最优解的)条件,关键在于估价函数f(n)的选取:
估价值h(n)<= n到目标节点的距离实际值,这种情况下,搜索的点数多,搜索范围大,效率低。但能得到最优解。并且如果h(n)=d(n),即距离估计h(n)等于最短距离,那么搜索将严格沿着最短路径进行, 此时的搜索效率是最高的。
如果 估价值>实际值,搜索的点数少,搜索范围小,效率高,但不能保证得到最优解。
- using UnityEngine;
- using System.Collections;
- using System.Collections.Generic;
- using System;
- /// <summary>
- /// 格子类型
- /// </summary>
- public enum GridType
- {
- Normal,
- Obstacle,
- Start,
- End
- }
- /// <summary>
- /// 为了实现格子的排序,继承ICompareable
- /// </summary>
- public class MapGrid:IComparable
- {
- /// <summary>
- /// 记录坐标
- /// </summary>
- public int x;
- public int y;
- /// <summary>
- /// 总消耗
- /// </summary>
- public int f;
- /// <summary>
- /// 当前到起点的消耗
- /// </summary>
- public int g;
- //当前到终点的消耗
- public int h;
- public GridType type;
- /// <summary>
- /// 父节点
- /// </summary>
- public MapGrid fatherNode;
- /// <summary>
- /// 排序
- /// </summary>
- /// <param name="obj"></param>
- /// <returns></returns>
- public int CompareTo(object obj)
- {
- MapGrid grid = (MapGrid)obj;
- if(this .f <grid .f)
- {
- //升序
- return -1;
- }
- if(this .f >grid .f)
- {
- //降序
- return 1;
- }
- return 0;
- }
- }
- public class AStar : MonoBehaviour {
- public int row = 5;
- public int col = 10;
- //格子大小
- public int size = 70;
- public MapGrid[,] grids;
- public ArrayList openList;
- public ArrayList closeList;
- //开始和结束的位置
- private int xStart = 2;
- private int yStart = 1;
- private int xEnd = 2;
- private int yEnd = 5;
- private Stack<string> fatherNodeLocation;
- void Init()
- {
- grids = new MapGrid[row, col];
- for (int i = 0; i < row; i++)
- {
- for (int j = 0; j < col; j++)
- {
- //初始化格子,记录格子的坐标
- grids[i, j] = new MapGrid();
- grids[i, j].x = i;
- grids[i, j].y = j;
- }
- }
- //开始点和其h的值
- grids[xStart, yStart].type = GridType.Start;
- grids[xStart, yStart].h = Manhatten(xStart, yStart);
- grids[xEnd, yEnd].type = GridType.End;
- fatherNodeLocation = new Stack<string>();
- for (int i = 1; i <= 3; i++)
- {
- grids[i, 3].type = GridType.Obstacle;
- }
- openList = new ArrayList();
- openList.Add(grids[xStart, yStart]);
- closeList = new ArrayList();
- }
- private int Manhatten(int x,int y)
- {
- return (int)(Math.Abs(xEnd - x) + Math.Abs(yEnd - y)) * 10;
- }
- void Start()
- {
- Init();
- }
- void DrawGrid()
- {
- for (int i = 0; i < row ; i++)
- {
- for (int j = 0; j < col ; j++)
- {
- Color color = Color.yellow;
- if(grids [i,j].type ==GridType .Start )
- {
- color = Color.green;
- }
- else if(grids [i,j].type ==GridType .Start )
- {
- color = Color.red;
- }
- else if (grids [i,j].type ==GridType .Obstacle )
- {
- color = Color.blue;
- }
- else if(closeList .Contains (grids [i,j]))
- {
- color = Color.yellow;
- }
- else
- {
- color = Color.grey;
- }
- GUI.backgroundColor = color;
- GUI.Button(new Rect(j * size, i * size, size, size), FGH(grids[i, j]));
- }
- }
- }
- private string FGH(MapGrid grid)
- {
- string str = "F" + grid.f + "\n";
- str += "G" + grid.g + "\n";
- str += "H" + grid.h + "\n";
- str += "(" + grid.x + "," + grid.y + ")";
- return str;
- }
- void OnGUI()
- {
- DrawGrid();
- for (int i = 0; i < openList .Count ; i++)
- {
- GUI.Button(new Rect(i * size, (row + 1) * size, size, size), FGH((MapGrid)openList[i]));
- }
- for (int j = 0; j < closeList .Count ; j++)
- {
- GUI.Button(new Rect(j * size, (row + 1) * size, size, size), FGH((MapGrid)closeList[j]));
- }
- if(GUI .Button (new Rect (col *size ,size ,size ,size ),"next"))
- {
- NextStep();
- }
- }
- private void NextStep()
- {
- if (openList.Count == 0)
- {
- print("over !");
- return;
- }
- MapGrid grid=(MapGrid )openList [0];
- if(grid.type ==GridType .End )
- {
- print ("find");
- ShowFatherNode(grid);
- return ;
- }
- for (int i = -1; i <=1; i++)
- {
- for (int j = -1; j <=1; j++)
- {
- int x = grid.x + i;
- int y = grid.y + j;
- if(x>=0&&x<row &&y>=0&&y<col&&
- grids [x,y].type !=GridType .Obstacle &&
- !closeList .Contains (grids[x,y]))
- {
- int g = grid.g + (int)(Math.Sqrt((Math.Abs(i) + Math.Abs(j))) * 10);
- if(grids[x,y].g==0||grids [x,y].g>g)
- {
- grids[x, y].g = g;
- grids[x, y].fatherNode = grid;
- }
- grids[x, y].h = Manhatten(x, y);
- grids[x, y].f = grids[x, y].g + grids[x, y].h;
- if(!openList .Contains (grids[x,y]))
- {
- openList.Add(grids[x, y]);
- }
- openList.Sort();
- }
- }
- }
- closeList.Add(grid);
- openList.Remove(grid);
- }
- private void ShowFatherNode(MapGrid grid)
- {
- if(grid.fatherNode !=null )
- {
- string str = grid.fatherNode.x + "," + grid.fatherNode.y;
- fatherNodeLocation.Push(str);
- ShowFatherNode(grid.fatherNode);
- }
- if(fatherNodeLocation .Count !=0)
- {
- print(fatherNodeLocation.Pop());
- }
- }
- }