a*算法初步(源代码)

关于a*算法的文章和代码有很多,这里是我整理的一份源代码,从别人的例子中修改过来的。在这个代码示例中加入了地图信息对寻址结果的影响,可以用在包含不同种类的地形信息的地图中寻址。由于代码可以调试,你可以看清楚每一个步骤是怎么做的,在这里我就不多做讲解了。
#include <windows.h>
#include <stdio.h>

#define COLS 3 //地图
#define ROWS 3
#define TOTAL_TILES 9

#define TileNum( x, y ) ( y * COLS + x + 1 ) //判断是地图上的第几个格子

struct NODE {
 long f,h,i; //在这里,我增加了一个i函数,主要用于地图信息
 int g;
 int x,y;
 int NodeNum;
 struct NODE *Parent;
 struct NODE *Child[8];       /* a node may have upto 8+(NULL) children. */
 struct NODE *NextNode;       /* for filing purposes */
};

struct NODE *OPEN;
struct NODE *CLOSED;

int TileMap[TOTAL_TILES] = { /  
1, 1, 1, /
1, 2, 1, /
1, 1, 1
};
//地图信息,目前由(0,0)点到(2,2)点的寻址结果是(0,0)->(1,1)->(2,2)。如果中间的那个2修改成4,表明不能行走或者是沼泽路面行走困难,寻址结果是(0,0)->(0,1)->(1,2)->(2,2)。

struct STACK {
    struct NODE *NodePtr;
    struct STACK *NextStackPtr;
};
struct STACK *Stack;

void Push(struct NODE *Node)
{
    struct STACK *tmp;
    tmp = ( struct STACK *)calloc(1,sizeof(struct STACK));
    tmp->NodePtr = Node;
    tmp->NextStackPtr = Stack->NextStackPtr;
    Stack->NextStackPtr = tmp;
}

struct NODE *Pop()
{
    struct NODE *tmp;
    struct STACK *tmpSTK;
    tmpSTK = Stack->NextStackPtr;
    tmp = tmpSTK->NodePtr;
    Stack->NextStackPtr = tmpSTK->NextStackPtr;
    free( tmpSTK );
    return( tmp );
}

struct NODE *CheckOPEN(int tilenum)
{
 struct NODE *tmp = OPEN->NextNode;
 while( tmp ) {
  if( tmp->NodeNum == tilenum )
   return( tmp );
  else
   tmp = tmp->NextNode;
 }
 return( NULL );
}

struct NODE *CheckCLOSED(int tilenum)
{
 struct NODE *tmp = CLOSED->NextNode;
 while( tmp ) {
  if( tmp->NodeNum == tilenum )
   return( tmp );
  else
   tmp = tmp->NextNode;
 }
 return( NULL );
}

void PropagateDown(struct NODE *Old)
{
 int c,g;
 struct NODE *Child, *Father;

 g = Old->g;
 for( c = 0; c < 8; c ++ ) {
  if( ( Child = Old->Child[c] ) == NULL ) break;
  if( g + 1 < Child->g ) {
   Child->g = g + 1;
   Child->f = Child->g + Child->h + Child->i;
   //Child->f = Child->g + Child->h;
   Child->Parent = Old;
   Push( Child );
  }
 }
 while( Stack->NextStackPtr != NULL ) {
  Father = Pop();
  for( c = 0; c < 8; c ++ ) {
   if( ( Child = Father->Child[c] ) == NULL ) break;
   if( Father->g + 1 < Child->g ) {
    Child->g = Father->g + 1;
    Child->f = Child->g + Child->h + Child->i;
    //Child->f = Child->g + Child->h;
    Child->Parent = Father;
    Push( Child );
   }
  }
 }
}

void Insert(struct NODE *Successor)
{
 struct NODE *tmp1,*tmp2;
 long f;

 if(OPEN->NextNode == NULL) {
  OPEN->NextNode = Successor;
  return;
 }

 f = Successor->f;
 tmp1 = OPEN;
 tmp2 = OPEN->NextNode;
 while( ( tmp2 != NULL ) && ( tmp2->f < f ) ) {
  tmp1 = tmp2;
  tmp2 = tmp2->NextNode;
 }
 Successor->NextNode = tmp2;
 tmp1->NextNode = Successor;
}

void GenerateSucc(struct NODE *BestNode,long x, long y, long dx, long dy)
{
 int g, TileNumS, c;
 struct NODE *Old,*Successor;

 TileNumS = TileNum( x, y );
 //g = BestNode->g + TileMap[TileNumS];
 g = BestNode->g + 1;

 if( ( Old = CheckOPEN(TileNumS) ) != NULL ) {
  for( c = 0; c < 8; c ++ ) {
   if( BestNode->Child[c] == NULL ) break;
  }
  BestNode->Child[c] = Old;
  if( g < Old->g ) {
   Old->Parent = BestNode;
   Old->g = g;
   Old->f = g + Old->h + Old->i;
   //Old->f = g + Old->h;
  }
 }
 else if( ( Old = CheckCLOSED(TileNumS) ) != NULL ) {
  for( c = 0; c < 8; c ++ ) {
   if( BestNode->Child[c] == NULL ) break;
  }
  BestNode->Child[c] = Old;
  if( g < Old->g ) {
   Old->Parent = BestNode;
   Old->g = g;
   //Old->f = g + Old->h;
   Old->f = g + Old->h + Old->i;
   PropagateDown( Old );
  }
 }
 else {
  Successor = (struct NODE *)calloc(1,sizeof( struct NODE ));
  Successor->Parent = BestNode;
  Successor->NodeNum = TileNumS;
  Successor->g = g;
  //Successor->h = abs( x - dx ) + abs( y - dy );
  Successor->h = ( x - dx ) * ( x - dx ) + ( y - dy ) * ( y - dy );
  Successor->i = TileMap[Successor->NodeNum-1];
  Successor->f = g + Successor->h + Successor->i;
  //Successor->f = g + Successor->h;
  Successor->x = x;
  Successor->y = y;
  Insert(Successor);
  for( c = 0; c < 8; c ++ ) {
   if( BestNode->Child[c] == NULL ) break;
  }
  BestNode->Child[c]=Successor;
 }
}

void GenerateSuccessors(struct NODE *BestNode,long dx,long dy)
{
 long x,y;

 /* Upper-Left  */
 x = BestNode->x - 1; y = BestNode->y - 1;
 if( x >= 0 && y >= 0 )
  GenerateSucc(BestNode,x,y,dx,dy);

 /* Upper       */
 x = BestNode->x; y = BestNode->y - 1;
 if( y >= 0 )
  GenerateSucc(BestNode,x,y,dx,dy);

 /* Upper-Right */
 x = BestNode->x + 1; y = BestNode->y - 1;
 if( x < COLS && y >= 0 )
  GenerateSucc(BestNode,x,y,dx,dy);

 /* Right       */
 x = BestNode->x + 1; y = BestNode->y;
 if( x < COLS )
  GenerateSucc(BestNode,x,y,dx,dy);

 /* Lower-Right */
 x = BestNode->x + 1; y = BestNode->y + 1;
 if( x < COLS && y < ROWS )
  GenerateSucc(BestNode,x,y,dx,dy);

 /* Lower       */
 x = BestNode->x; y = BestNode->y + 1;
 if( y < ROWS )
  GenerateSucc(BestNode,x,y,dx,dy);

 /* Lower-Left  */
 x = BestNode->x - 1; y = BestNode->y + 1;
 if( x >= 0 && y < ROWS )
  GenerateSucc(BestNode,x,y,dx,dy);

 /* Left        */
 x = BestNode->x - 1; y = BestNode->y;
 if( x >= 0 )
  GenerateSucc(BestNode,x,y,dx,dy);
}

struct NODE *ReturnBestNode(void)
{
 struct NODE *tmp;
 tmp = OPEN->NextNode;
 OPEN->NextNode = tmp->NextNode;
 tmp->NextNode = CLOSED->NextNode;
 CLOSED->NextNode = tmp;
 return(tmp);
}

struct NODE *FindPath(long sx, long sy, long dx, long dy)
{
 struct NODE *Node, *BestNode;
 int TileNumDest = TileNum(dx,dy);
 OPEN = (struct NODE *)calloc(1,sizeof( struct NODE ));
 CLOSED = (struct NODE *)calloc(1,sizeof( struct NODE ));

 Node=(struct NODE *)calloc(1,sizeof( struct NODE ));
 Node->NodeNum = TileNum(sx,sy);
 Node->g = 0;
 //Node->h = abs( sx - dx ) + abs( sy - dy );
 Node->h = ( sx - dx ) * ( sx - dx ) + ( sy - dy ) * ( sy - dy );
 Node->i = TileMap[Node->NodeNum-1];
 Node->f = Node->g + Node->h + Node->i;
 //Node->f = Node->g + Node->h;
 Node->x = sx;
 Node->y = sy;

 OPEN->NextNode=Node;
 for (;;) {
  BestNode = (struct NODE *)ReturnBestNode();
  if( BestNode->NodeNum == TileNumDest ) break;
  GenerateSuccessors( BestNode, dx, dy );
 }
 return BestNode;
};

INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
 Stack=( struct STACK *)calloc(1,sizeof(struct STACK));
 struct NODE * Path = FindPath( 0, 0, 2, 2 );
 return 0;
}

虽然用上面的算法可以找到目的地址,但是目前有几个问题:
1)效率问题:当起点到终点的路径不存在的时候,a*的花费比较大,应该加如预寻址算法或者改进当前算法。
2)当地图中不能走的地方边边角角较多的时候,寻址的结果中折线较多,此时可以寻求其次优解,将路径美化。
3)寻址方向目前有8个,对应于2D的八个方向,感觉应该能扩展到3D空间当中,做一个3D的a*寻址。3D寻址的时候应该是26个方向。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
此为用C#写的A*算法源代码 using System; using System.Collections.Generic; using System.Text; using System.Drawing; namespace EtSoft.AStarLib { public class AStar { private StarNodeCollection openList = new StarNodeCollection(); private StarNodeCollection closeList = new StarNodeCollection(); public StarNode currentNode = null; #region 构造函数 /// <summary> /// 使用指定的地图对象、起点和终点初始化A星算法 /// </summary> /// <param name="map">地图对象</param> public AStar(Map map) { this.map = map; } /// <summary> /// /// </summary> /// <param name="map">地图对象</param> /// <param name="start">起点坐标</param> /// <param name="end">终点坐标</param> public AStar(Map map, Point start, Point end) : this(map) { this.start = new StarNode(start); this.end = new StarNode(end); openList.Add(new StarNode(start)); //AddStartNodeToOpenList(this.start); } /// <summary> /// /// </summary> /// <param name="map">地图对象</param> /// <param name="startX">起点X坐标</param> /// <param name="startY">起点Y坐标</param> /// <param name="endX">终点X坐标</param> /// <param name="endY">终点Y坐标</param> public AStar(Map map, int startX, int startY, int endX, int endY) : this(map, new Point(startX, startY), new Point(endX, endY)) { } #endregion #region 属性 protected Map map; /// <summary> /// 地图数据 /// </summary> public Map Map { get { return map; } set { map = value; } } private StarNode start = null; /// <summary> /// 起点坐标,如果没有设置起点,返回null /// </summary> public StarNode Start { get { return start; } set { start = value; openList.Clear(); openList.Add(start); //AddNodeToOpenList(start); } } private StarNode end = null; /// <summary> /// 终点坐标,如果没有设置终点,返回null /// </summary> public StarNode End { get { return end; } set { end = value; } } private StarNodeCollection path; /// <summary> /// 返回路径节点集合,没有路径则返回null /// </summary> public StarNodeCollection Path { get { return path; } } private bool allDirection = false; /// <summary> /// true,允许八方向寻路 /// </summary> public bool AllDirection { get { return allDirection; } set { allDirection = value; } } #endregion /// <summary> /// 开始寻路 /// </summary> public void StartSearchPath() { if (start == null) throw new InvalidNodeException(InvalidNodeTypes.NoStart); if (end == null) throw new InvalidNodeException(InvalidNodeTypes.NoEnd); path = null; openList.Clear(); closeList.Clear(); currentNode = start; SearchPath(currentNode); } //寻路递归,受保护的虚方法,允许在子类重写寻路算法 protected virtual void SearchPath(StarNode starNode) { //currentNode = starNode; openList.Remove(starNode); closeList.Add(starNode); AddNodeToOpenList(); if (closeList.Contains(end)) { //如果终点在关闭列表中,找到路径 StarNode node=starNode.Parent; path = new StarNodeCollection(); do { path.Add(node); node = node.Parent; } while (node != null && !node.Equals(start)); path.Reverse(); return; } else if (openList.Count == 0) { //终点不在关闭列表,开放列表已空,没有可通行的路径 return; } currentNode = GetNextNode(); //迭代过程 SearchPath(currentNode); } /// <summary> /// 获得当前节点的下一个最佳节点 /// </summary> /// <returns></returns> public StarNode GetNextNode() { openList.SortByF(); return openList[0]; } /// <summary> /// 把当前点周围可通过的点加入到开放列表中 /// </summary>
A*算法是一种常用的启发式搜索算法,用于求解图的最短路径问题。它结合了广度优先搜索和启发式搜索的特点,能够高效地找到最优路径。 下面是一个基于A*算法的Matlab代码示例: ```matlab function path = aStarAlgorithm(graph, start, goal) openList = PriorityQueue(); % 创建一个优先队列用于存放待扩展的节点 openList.insert(start, 0); % 将起始节点加入openList中 cameFrom = containers.Map; % 存放节点的父节点,用于回溯路径 gScore = containers.Map; % 存放节点的实际代价 gScore(start) = 0; % 起始节点的实际代价为0 fScore = containers.Map; % 存放节点的估计代价 fScore(start) = heuristicCostEstimate(start, goal); % 起始节点的估计代价为启发式函数值 while ~openList.isEmpty() current = openList.pop(); % 从openList中取出fScore最小的节点 if current == goal path = reconstructPath(cameFrom, goal); % 回溯路径 return; end neighbors = getNeighbors(graph, current); % 获取当前节点的邻居节点 for i = 1:length(neighbors) neighbor = neighbors(i); tentativeGScore = gScore(current) + distance(current, neighbor); % 计算从起始节点到邻居节点的实际代价 if ~isKey(gScore, neighbor) || tentativeGScore < gScore(neighbor) cameFrom(neighbor) = current; gScore(neighbor) = tentativeGScore; fScore(neighbor) = gScore(neighbor) + heuristicCostEstimate(neighbor, goal); if ~openList.contains(neighbor) openList.insert(neighbor, fScore(neighbor)); % 将邻居节点加入openList中 end end end end end ``` 以上代码是一个简单的A*算法实现,其中包括了节点的存储、优先队列的使用、启发式函数的定义等基本步骤。通过这个示例,我们可以看到A*算法的基本思想和实现方式,能够帮助我们更好地理解和应用这个经典的搜索算法

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值