c语言实现a*算法

最近要实训需要实现迷宫,所以就先实现了之前一直总是了解算法思路的a算法。最开始我是想凭借自己对于这个寻路算法的理解,完全的按照自己的思路实现,最后结果感人,在实现函数的传递时候,才发现自己对于c语言函数参数传递的概念有些理解错误,导致一直有错误。再我测试了多次,终于发现是由于函数参数传递使用有误,在这里我分享以下自己所遇见的错误吧,并且把自己实现的a算法,所讲一下。

函数参数传递

c语言中的函数传递方式总共有三种:
1.直接将数值传入函数中,这时函数中的形参在函数未调用前是不会分配存储空间的,只有在函数调用过程中会生成一个局部变量,这种方式,会浪费存储空间,所以如果是传递自己所定义的结构体数据类型建议传递地址。并且这个局部变量的值为实参的值,修改这个形参无法对于实参的值进行修改。
2.将实参地址传入函数,这时函数获取了实参的地址,可以通过修改这个地址所指向的变量的值,来修改实参的值。
3.声明,通过这个方式也可修改实参的值。
例如,

#include<stdio.h>
void a(int b,int &c,int *e);
void a(int b,int &c,int *e){
 b=20;
 c=30;
 *e=10;
}
void main(){
 int b,c,e;
 b=10;
 c=10;
 e=20;
 a(b,c,&e);
 printf("b=%d,c=%d,e=%d",b,c,e);
}

在这个例子里,在主函数中,b=10,c=10,e=20;
而通过调用这个a()函数后,通过调用结果,输出的结果为b=10,c=30,e=10;通过这个应该能够理解c语言中函数参数的传递。

A*算法的思路

A算法的详解,可以在以下地址去学习,这是我早些时候学习a算法思路所观看的博客
a*算法思路
讲下基本思路:
1.将起始点加入openlist之中
2.将openlist中的F值最小的节点移到closelist中
3.检测以这个点为中心的邻近8个点:

  • 检测是否越界,若越界则忽略
  • 检测是否为不可行走点,若是则忽略
  • 检测是否在closelist中,在则忽略
  • 检测是否在openlist中,若不在则将只加入openlist中
  • 检测若该点在openlist中,则比较这个点与它的父亲的G值,取G值小的,并把该点的F值重新计算。
    4.重复进行2,3步的操作,直至在closelist中检测到终点.这时closelist就是这个路径。
A*算法实现代码

头文件源代码

#include<stdio.h>
#include<stdlib.h>
#define MAXSIZE 50
typedef struct node {
 int data;
 int G;
 int F;
 int H;
 int x;
 int y;
 struct node* father;
}node;
typedef struct {
 int b[MAXSIZE];
}datatype;
typedef struct {
 datatype a[MAXSIZE];
 int x, y;
}Array2;
typedef struct {
 node data[MAXSIZE + 1];//L[0]当做一个利用的储存单位,没有用来存储节点
 int len;
}Array1;

函数声明

void del(Array1* L, int index);//删除指定位置的节点需修改
void append(Array1* L, node p);
Array1 *startAstar(Array2* L, node *startpath, node* lastpath);//开始进行A星寻路
void init_Array(Array1* L);
int judge_out(Array1* L, node lastpath);
void print_Array(Array2* G);//打印地图
int getMinNode(Array1* L);
int getdex(Array1* L, node* p);
void searchNear(Array1* L, node* minF, int offsetx, int offsety,Array2* G,Array1* L2,node* lastnode);

函数实现

int getdex(Array1* L, node* p) {
 int i;
 for (i = 1;i <= L->len;i++) {
  if (L->data[i].x == p->x && L->data[i].y == p->y)
   return i;
 }
}
void searchNear(Array1* L, node* minF, int offsetx, int offsety,Array2* G,Array1* L2 ,node* lastnode) {
 int step;
 if (minF->x + offsetx<0 || minF->x + offsetx>G->x - 1 || minF->y + offsety<0 || minF->y + offsety>G->y - 1)//判断是否越界
  return;
 if (G->a[minF->x + offsetx][minF->y + offsety] != 0)//判断是否可行走
  return;
 node* p;
 p = (node*)malloc(sizeof(node));
 p->x = minF->x + offsetx;
 p->y = minF->y + offsety;
 p->G = 0;
 p->father = NULL;
 if (judge_out(L2, *p))//判断是否在封闭列表中,若在则返回
  return;
 if (offsetx == 0 || offsety == 0)
  step = 10;
 else step = 14;
 if (!judge_out(L, *p)) {     //若该点既满足以上条件又不在开放列表中,则加入开放列表
  p->H = (abs(lastnode->x - p->x) + abs(lastnode->y - p->y)) * 10;
  p->G = minF->G + step;
  p->F = p->H + p->G;
  p->father = minF;
  append(L, *p);
  return;
 }
 if (judge_out(L, *p)) {
  if (minF->G + step < L->data[getdex(L,p)].G) {  //若该点满足以上条件但是在开放列表中,则与当前加入closelist的最小F点到这个点P利用G值做比较,选择G值小的。然后做出以下操作
   L->data[getdex(L,p)].G = minF->G + step;
   L->data[getdex(L, p)].F = L->data[getdex(L, p)].G + L->data[getdex(L, p)].H;
   L->data[getdex(L, p)].father = minF;
  }
 }
}
int getMinNode(Array1 *L) {
 int i,count=1;
 for (i = 2;i <= L->len;i++)
  if (L->data[count].F > L->data[i].F)
   count = i;
 return count;
}
void print_Array(Array2* G) {
 int i, j;
 for (i = 0;i < G->x;i++) {
  for (j = 0;j < G->y;j++)
   printf("%d\t", G->a[i][j]);
  printf("\n");
 }
}
int judge_out(Array1* L, node lastpath) {
 int i;
 for (i = 1;i <= L->len;i++) {
  if (L->data[i].x == lastpath.x && L->data[i].y == lastpath.y)
   return 1;
 }
 return 0;
}
void init_Array(Array1* L) {
 int i;
 for (i = 0;i <= MAXSIZE;i++)
  L->data[i].F = 999;
 L->len = 0;
}
void append(Array1* L, node p) {
 L->len++;
 L->data[L->len] = p;
}
Array1* startAstar(Array2* L, node *startpath, node *lastpath) {
 Array1 openlist, closelist,shortpath;
 init_Array(&openlist);//初始化开放列表和封闭列表
 init_Array(&closelist);
 init_Array(&shortpath);
 if (L->a[startpath->x][startpath->y] == 1)//检测起始点是否为障碍,若为障碍则退出,返回NULL型
  return NULL;
 append(&openlist, *startpath);//将起点加入到开放列表中
 while (1) {   //主循环中
  int p;
  node q;
  p = getMinNode(&openlist);//利用p储存找到的具有最小F值点在openlist中的位置
  //q = openlist.data[p];//获取具有最小F值的节点,将之存于q  //有问题
  append(&closelist, openlist.data[p]);//将该节点加入到封闭列表中
  del(&openlist, p);//将开放列表中的该节点删除
  searchNear(&openlist, &closelist.data[closelist.len], 0, -1, L, &closelist, lastpath);//搜索具有最小F值点上下左右点,判断是否满足条件,满足则加入openlist中
  searchNear(&openlist, &closelist.data[closelist.len], 0, 1, L, &closelist, lastpath);
  /*searchNear(&openlist, &closelist.data[closelist.len], 1, 1, L, &closelist, lastpath);
  searchNear(&openlist, &closelist.data[closelist.len], 1, -1, L, &closelist, lastpath);
  searchNear(&openlist, &closelist.data[closelist.len], -1, 1, L, &closelist, lastpath);
  searchNear(&openlist, &closelist.data[closelist.len], -1, -1, L, &closelist, lastpath);*/
  searchNear(&openlist, &closelist.data[closelist.len], -1, 0, L, &closelist, lastpath);
  searchNear(&openlist, &closelist.data[closelist.len], 1, 0, L, &closelist, lastpath);
  if (judge_out(&openlist, *lastpath)) {//寻路结束判断,当终点进入开放列表则退出寻路
   node* m;
   m = (node*)malloc(sizeof(node));
   m = &openlist.data[getdex(&openlist, lastpath)];
   while (1) {
    if (m == NULL)
     break;
    append(&shortpath, *m);
    m = m->father;
   }
   return &shortpath;
  }
  if (openlist.len == 0)
   //return &closelist;//在该迷宫中所走的路径
   return NULL;
 }
}
void del(Array1* L, int index) {
 int i;
 for (i = index;i <=L->len;i++) {
  L->data[i] = L->data[i + 1];
 }
 L->len--;
}

主函数代码

#include"AStar2.h"
void init_G(Array2* G);
void init_G(Array2* G) {
 int i, j;
 for (i = 0;i < G->x;i++)
  for (j = 0;j < G->y;j++)
   G->a[i].b[j] = 0;
}
void main() {
 Array2 G;
 Array1* P;
 node a, b;
 int i;
 G.x = 10;
 G.y = 10;
 init_G(&G);
 for (i = 0;i < 8;i++)
  G.a[i].b[5] = 1;
 a.x = 5;
 a.y = 0;
 a.data = 0;
 a.G = 0;
 a.F = 0;
 b.x = 0;
 b.y = 07;
 print_Array(&G);
 printf("\n");
 P = startAstar(&G, &a, &b);
 if (P != NULL) {
  for (i = 1;i < P->len;i++)
   G.a[P->data[i].x].b[P->data[i].y] = 8;
 }
 print_Array(&G);
}

结果截图:
结果截图
以1为障碍,第一个二维数组为原地图,第二个为添加了行走路径的地图。其中,8为行走路径。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值