码迷,mamicode.com
首页 > 编程语言 > 详细

A*寻路算法的探寻与改良(三)

时间:2015-12-20 14:30:01      阅读:232      评论:0      收藏:0      [点我收藏+]

标签:

A*寻路算法的探寻与改良(三)

by:田宇轩                                       

第三分:这部分内容基于树、查找算法等对A*算法的执行效率进行了改良,想了解细化后的A*算法和变种A*算法内容的朋友们可以跳过这部分并阅读稍后更新的其他内容

3.1 回顾

       在我的上一篇文章中,我们探讨了如何用编程实现A*算法,并给出了C语言的算法实现,这一章内容中我们主要研究如何提高A*算法的执行效率。抛开时间复杂度的复杂计算,我们大概可以知道,函数对数据的操作次数越少,达成目的越快,算法的效率也就越高。沿着这个思路,我们可以先从研究函数对存储结构做的操作频率和具体内容改造它们,使A*更高效。如果前两部分只是初学者的新手教程,那么从本章开始,我们进入了更难的部分。

 

3.2 分析A*函数的中代价高的操作

      在A*中,我们把起点放入iter,然后就重复for循环,可见for循环中重复执行的函数对于A*算法性能的影响是非常重要的,我们就从这个Astar里的最外层for循环开始看,一个函数一个函数地分析出哪个部分可以如何提高A*算法的效率。

     (一)首先我们分析的就是这个for循环的循环条件,这个循环的条件在每一次循环发生的时候都会进行判定。最外层的for循环里,我们只判定这么两项内容:

     (1)开启列表是否为空。开启列表如果是空的,这就代表我们没有待处理的格子了,已经无路可走,因此开启列表一旦为空,A*算法也就不用执行了。但是看过上一篇文章的朋友应该记得,我们用一个有全局作用域的变量openListCount(引用代码内容用基佬紫色,下同)来记录开启列表里格子的个数,因此,这个判定就只是判定openListCount这个参数是否为0,这种判定很简单,因此不用优化

     (2)终点是否在关闭列表中。一旦终点在关闭列表之中,就说明我们已经找到了最优路径,并且把路径的最有一个格子——终点也进行了父节点标记的操作,这一操作之后,A*也不必继续下去了。回顾上一篇文章,我们是在关闭列表中逐一匹配里面格子的坐标是否和终点坐标相等,这其实是很麻烦的方法。那么,怎么检测终点是否在关闭列表中呢,这里有一个更好的思路:我们都知道起点是唯一一个G值为0的格子(起点距离自己的距离为0),相应的,终点也是唯一一个H值为0的格子。在求曼哈顿距离时,如果发现一个格子的H值为0,那么毫无疑问,这个格子就是终点。我们可以用一个标记(类似process_control.h里面的参数flag一样)来使主循环停止而不用一一匹配新格子与关闭列表。

    (二)主循环分析完了,我们来看看迭代器进入循环体内部发生的事情。之后首先发生的事情,是一个查找操作,开启列表中F值最小的(之一)会被找出来并设为当前格。然后是一个把当前格放入关闭列表的操作。先分析这两步操作:

    (1)查找开启列表中的最小值。之前这一步操作中我们用的是冒泡排序的一层循环,把它们中最小的数(之一)沉到底,但是这种查找方法显然并不快,开启列表是在稍后的迭代操作中一步一步建立起来的,因此我们每次把东西加入开启列表可以按照最小二叉堆的添加操作做,这样数组的最后一个元素自然就是开启列表中最大的元素(之一)了。

    (2)往开启列表中插入新的元素。开启列表是最小二叉堆,因此插入元素要根据最小二叉堆的性质。

    (3)删除开启列表中最小的元素。开启列表是最小二叉堆,因此删除元素要根据最小二叉堆的性质。

    (4)删除开启列表中指定的元素。开启列表中元素的f值可能会随着重新计算NewG的值而改变,因此我们会先删除指定的元素。这个过程可以有很多种方式实现,这里,我的例子选择完全重新排序开启列表,其实不是很有效率。

    (5)把当前元素加入关闭列表,用方便查找的方式构建关闭列表使其易于查找。

    (6)搜索关闭列表,配合关闭列表结构提高效率。

     因此,我们可以总结出7条可以优化的操作(函数):

     (1)void putInOpenList(struct baseNode inList),把一个元素插入开启列表中。开启列表主要是插入删除,因此用最小二叉堆就好了,每次都出队列最小的数字,改进后要求格子按照最小二叉堆的性质进行插入操作。

     (2)struct baseNode readTopOpenList(),取出开启列表中最小的数字。改进后这个函数根据最小二叉堆的性质直接获取列表顶部格子即可。

     (3)void putInCloseList(struct baseNode temp),当前点加入到关闭列表中。关闭列表只有插入和搜索操作,为了方便检索,可以按照二叉排序树、AVL树或者红黑树的性质做一个关闭列表的操作(然而我并不会红黑树,(逃(哔站粉用于标记吐槽和没什么卵用的内心独白,下同),等我学完红黑树就回来补完这个~QwQ),这里,为了简单(其实只是自己水平有限),做一个方便查找的普通排序列表配合折半查找好了。

     (4)void outOpenList(struct baseNode iter),把开启列表中的当前节点删除。既然开启列表是最小二叉堆,删除也要按照这个性质来。
     (5)void outopenlist2(struct baseNode iter),
重新排序最小二叉堆,并删除指定的点。

     (6)int isInCloseList(struct baseNode temp),查看指定的temp在不在关闭列表中的函数,用折半查找提高效率就好了。

     (7)int manhatten(int i, int j),求曼哈顿函数的值,当值为零,赶紧立一个flag,让主循环停止。

      OpenList和CloseList的存储结构也随着新设计的数据结构改变就好,明确了这些重点,剩下的活只要实现这些函数,然后把函数覆盖原来的函数(位于func.h中)就好。

 

3.3 实现7条优化

      下面的内容就是这些函数的具体实现。

3.3.1 优化终点在不在关闭列表的判定

      首先,我们对比较简单的(7)int manhatten(int i, int j),进行改造如下:

 1 //A*中的启发式函数,用于求指定位置和终点之间的曼哈顿距离
 2 int manhatten(int i, int j)
 3 {
 4     int a= (abs(AsceneryList[1].node.i - i) + abs(AsceneryList[1].node.j - j));
 5     if (a==0)
 6     {
 7         FLAG = 1;
 8     }
 9 
10     return a*10;
11 }

代码3.3.1.1——改造后的manhatten

    这里,我们在data.h里定义一个全局变量,int FLAG=0;,这个FLAG初值为0,每当Astar执行中发现某个格子曼哈顿距离为0,相应地,就把这个FLAG的值改为1,然后Astar内最外层for循环判定条件发现FLAG等于1,就意味着终点已经在关闭列表内,可以松口气了(以前是遍历关闭列表找终点在不在里面,这显然是一步优化)。但是相应地,改变Astar最外层for语句为for (;  openListCount != 0 && FLAG==0;)。

    同时别忘了每次执行Astar前都重置FLAG值为1,只需在Astar函数内开始加上一句FLAG=0;。

3.3.2 优化开启列表

    函数(1)(2)(4)(5)都和开启列表有关,分别对应着开启列表的添加元素,最小值出队列,删除元素和搜索,我们这里再处理他们,改为下面这样的函数:

 1 //把一个元素插入开启列表中/////////
 2 void putInOpenList(struct baseNode inList)
 3 {
 4     ++openListCount;
 5 
 6     OpenList[openListCount - 1] = inList;
 7     for (int i = openListCount - 1; i >0; i=(i-1)/2)
 8     {
 9         if (OpenList[i].f<OpenList[(i-1)/2].f)
10         {
11             OpenList[i]=OpenList[(i - 1) / 2];
12             OpenList[(i - 1) / 2] = inList;
13         }
14         else
15         {
16             break;
17         }
18     }
19 }
20 
21 //取出开启列表中最小的数
22 struct baseNode readTopOpenList()
23 {
24     return OpenList[0];
25 }
26 
27 //把开启列表中的当前节点删除
28 void outOpenList()
29 {
30     --openListCount;
31 
32     OpenList[0]=OpenList[openListCount];
33     struct baseNode temp;
34 
35     for (int i = 0,p=0; 2*i+1<openListCount;i=p)
36     {
37         if (2*i+2>openListCount-1)
38         {
39             p = 2 * i + 1;
40         }
41         else
42         {
43             if (OpenList[2 * i + 1].f<OpenList[2 * i + 2].f)
44             {
45                 p = 2 * i + 1;
46             }
47             else
48             {
49                 p = 2 * i + 2;
50             }
51         }
52 
53         if (OpenList[p].f<OpenList[i].f)
54         {
55             temp=OpenList[p];
56             OpenList[p]=OpenList[i];
57             OpenList[i] = temp;
58         }
59         else
60         {
61             break;
62         }
63     }
64 }
65 
66 //删除开启列表中指定的元素,重构最小二叉堆
67 //(注:这个可以用很多方法实现,示例并非最优)
68 void outOpenList2(struct baseNode iter)
69 {
70     int number=openListCount-1;
71     struct baseNode openlist2[MAX_number*MAX_number];
72     for (int i = 0; i < openListCount; ++i)
73     {
74         if (OpenList[i].i==iter.i&&OpenList[i].j==iter.j)
75         {
76             continue;
77         }
78         openlist2[i]=OpenList[i];
79     }
80 
81     openListCount = 0;
82     for (int i = 0; i < number; ++i)
83     {
84         putInOpenList(openlist2[i]);
85     }
86 }

代码3.2.2.1——优化开启列表

 3.3.3 优化关闭列表

       关闭列表中的元素是只进不出的,因此这里用简单的排序+折半查找优化效率,注意:对于关闭列表中的排序,应该用唯一值做key方便折半查找,这里,唯一key被设置成为格子的i坐标乘地图边的最大值加上格子的j坐标:

 1 //把一个元素加入关闭列表中
 2 void putInCloseList(struct baseNode temp)
 3 {
 4     CloseList[closeListCount] = temp;
 5 
 6     struct baseNode iter;
 7     for (int i = closeListCount; i>0; --i)
 8     {
 9         if ((CloseList[i].i*MAX_number+CloseList[i].j+1)<(CloseList[i-1].i*MAX_number + CloseList[i-1].j + 1))
10         {
11             iter = CloseList[i];
12             CloseList[i]=CloseList[i - 1];
13             CloseList[i - 1] = iter;
14         }
15         else
16         {
17             break;
18         }
19     }
20     ++closeListCount;
21 }
22 
23 //查看指定的temp在不在关闭列表中的函数
24 int isInCloseList(struct baseNode temp)
25 {
26     int low = 0, high = closeListCount - 1, mid = (low + high) / 2;
27 
28     for (; low<=high; mid = (low + high) / 2)
29     {
30         if ((CloseList[mid].i*MAX_number + CloseList[mid].j + 1)==(temp.i*MAX_number + temp.j + 1))
31         {
32             return 1;
33         }
34         else if((CloseList[mid].i*MAX_number + CloseList[mid].j + 1) > (temp.i*MAX_number + temp.j + 1))
35         {
36             high = mid - 1;
37         }
38         else
39         {
40             low = mid + 1;
41         }
42     }
43     return 0;
44 }

代码3.3.3.1——优化关闭列表

      这里要说明一下思路,我们为了使关闭列表方便查找,使用了插入新元素时排序关闭列表的方式,排序依赖的值应该类似主码,是格子唯一的标记,格子存储在二维数组中,唯一标记显然是格子的坐标,不过坐标是两个值,我们不想弄一个结构体储存格子的key,所以就采用哈希表的思路把格子的横纵坐标转换为一个唯一值,那就是一个格子在二维列表的次序(这个格子在二维列表中是第几个格子)。

3.3 回顾

      这样所有的函数就优化完了,这组优化只改动了func.hdata.h,现在我们把改进后的这两个文件重新贴在下方(默认折叠),如果大家在自己按照这种思路写A*遇到困难,可以参考以下内容:

技术分享
 1 #pragma once
 2 
 3 #define MAX_number 5
 4 
 5 //一个比较基础的结构体,用于和地图联动
 6 struct baseNode
 7 {
 8     int i;
 9     int j;
10     int weigt;
11 
12     int f;
13     int g;
14     int h;
15 
16     struct baseNode *father;
17 };
18 
19 //定义了一个全局变量用来存储二维矩阵地图
20 struct baseNode map[MAX_number][MAX_number];
21 
22 //用于记录景点的数组元素
23 struct scenerySpotsList
24 {
25     struct baseNode node;
26     char placeName[20];
27 };
28 
29 //邻居列表,用于记录每个当前点的所有邻居
30 struct baseNode Neibo[8];
31 
32 //记录景点,起点和终点的数组
33 struct scenerySpotsList AsceneryList[MAX_number*MAX_number];
34 
35 //开启列表,用于A*算法
36 struct baseNode OpenList[MAX_number*MAX_number];
37 
38 //关闭列表,用于A*算法
39 struct baseNode CloseList[MAX_number*MAX_number];
40 
41 //用于记录现在的景点个数,第1个景点记录在AsceneryList【2】里,AsceneryList【0】和AsceneryList【1】分别用来记录起点和终点
42 int sceneryCount = 2;
43 
44 //用于记录开启列表中元素的个数
45 int openListCount = 0;
46 
47 //用于记录关闭列表中元素的个数
48 int closeListCount = 0;
49 
50 //用于记录邻居的个数
51 int neibNum = 0;
52 
53 //用来储存整理后的路径
54 struct baseNode Astack[MAX_number*MAX_number];
55 
56 //用来记录路径经过的点的个数
57 int AstackCount = 0;
58 
59 //用于记录关闭列表里是否有终点
60 int FLAG = 0;
data.h
技术分享
  1 #pragma once
  2 
  3 #include <stdio.h>
  4 #include <stdlib.h>
  5 #include <string.h>
  6 #include <math.h>
  7 #include "data_define.h"
  8 
  9 //设定地图的函数
 10 void inputmap()
 11 {
 12     printf("目前地图大小为%d * %d。\n",MAX_number,MAX_number);
 13     printf("请通过输入整数的形式填充地图,0代表地形不可通过,\n其他正整数代表权值,权值越大,地形越不方便通过\n\n");
 14 
 15     for (int i = 0; i <MAX_number; ++i)
 16     {
 17         for (int j = 0; j < MAX_number; ++j)
 18         {
 19             scanf("%d", &map[i][j].weigt);
 20 
 21             map[i][j].i = i;
 22             map[i][j].j = j;
 23         }
 24         printf("第%d行输入完毕,共%d行\n\n",i+1,MAX_number);
 25     }
 26 }
 27 
 28 //设定校园景点的函数
 29 void setView()
 30 {
 31     for (; ; )
 32     {
 33         int inputI = 0;
 34         int inputJ = 0;
 35         char inputS[20];
 36 
 37         printf("请输入景点的名称,输入done结束景点录入\n");
 38         scanf("%s", inputS);
 39 
 40         if (strcmp(inputS,"done")==0)
 41         {
 42             printf("结束输入:\n");
 43             break;
 44         }
 45         else
 46         {
 47             strcpy(AsceneryList[sceneryCount].placeName,inputS);
 48 
 49             printf("地图坐标从【1,1】开始\n");
 50             printf("请输入景点的横坐标:\n");
 51             scanf("%d", &inputI);
 52             AsceneryList[sceneryCount].node.i = inputI-1;
 53 
 54             printf("请输入景点的纵坐标:\n");
 55             scanf("%d", &inputJ);
 56             AsceneryList[sceneryCount].node.j = inputJ-1;
 57 
 58             printf("成功输入一个景点:\n");
 59             ++sceneryCount;
 60         }
 61     }
 62 }
 63 
 64 //设定起点和终点的函数
 65 void setRoad()
 66 {
 67     printf("你可以进行以下操作\n");
 68     printf("1.寻找一个景点\n");
 69     printf("2.手动设定起点终点坐标\n");
 70 
 71     int user_input = 0;
 72     scanf("%d",&user_input);
 73 
 74     if (user_input==1)
 75     {
 76         int i = 2;
 77 
 78         char inputS[20];
 79         printf("请输入想查找的景点的名称:\n这个景点将作为起点\n");
 80         scanf("%s", inputS);
 81 
 82         for (; i < sceneryCount; ++i)
 83         {
 84             if (strcmp(AsceneryList[i].placeName, inputS) == 0)
 85             {
 86                 AsceneryList[0].node = AsceneryList[i].node;
 87 
 88                 i = 0;
 89                 printf("成功把%s设置为起点\n",inputS);
 90                 break;
 91             }
 92         }
 93         if (i != 0)
 94         {
 95             printf("找不到这个景点\n");
 96         }
 97 
 98         int j = 2;
 99 
100         char inputM[20];
101         printf("请输入想查找的景点的名称:\n这个景点将作为终点\n");
102         scanf("%s", inputM);
103 
104         for (; j < sceneryCount; ++j)
105         {
106             if (strcmp(AsceneryList[j].placeName, inputM) == 0)
107             {
108                 AsceneryList[1].node = AsceneryList[j].node;
109 
110                 j = 0;
111                 printf("成功把%s设置为终点\n",inputM);
112                 break;
113             }
114         }
115         if (j!=0)
116         {
117             printf("找不到这个景点\n");
118         }
119     }
120     else if(user_input==2)
121     {
122         int i = 0, j = 0, p = 0, q = 0;
123 
124         printf("地图坐标从【1,1】开始\n");
125         printf("请输入起点的横坐标:\n");
126         scanf("%d", &i);
127         printf("请输入起点的纵坐标:\n");
128         scanf("%d", &j);
129 
130         AsceneryList[0].node.i = i - 1;
131         AsceneryList[0].node.j = j - 1;
132 
133         printf("请输入终点的横坐标:\n");
134         scanf("%d", &p);
135         printf("请输入终点的纵坐标:\n");
136         scanf("%d", &q);
137 
138         AsceneryList[1].node.i = p - 1;
139         AsceneryList[1].node.j = q - 1;
140     }
141     else
142     {
143         printf("输入错误\n");
144     }
145 }
146 
147 //以下函数都是A*算法的一部分///////////////////////////
148 
149 //把一个元素插入开启列表中/////////
150 void putInOpenList(struct baseNode inList)
151 {
152     ++openListCount;
153 
154     OpenList[openListCount - 1] = inList;
155     for (int i = openListCount - 1; i >0; i=(i-1)/2)
156     {
157         if (OpenList[i].f<OpenList[(i-1)/2].f)
158         {
159             OpenList[i]=OpenList[(i - 1) / 2];
160             OpenList[(i - 1) / 2] = inList;
161         }
162         else
163         {
164             break;
165         }
166     }
167 }
168 
169 //取出开启列表中最小的数
170 struct baseNode readTopOpenList()
171 {
172     return OpenList[0];
173 }
174 
175 //把一个元素加入关闭列表中
176 void putInCloseList(struct baseNode temp)
177 {
178     CloseList[closeListCount] = temp;
179 
180     struct baseNode iter;
181     for (int i = closeListCount; i>0; --i)
182     {
183         if ((CloseList[i].i*MAX_number+CloseList[i].j+1)<(CloseList[i-1].i*MAX_number + CloseList[i-1].j + 1))
184         {
185             iter = CloseList[i];
186             CloseList[i]=CloseList[i - 1];
187             CloseList[i - 1] = iter;
188         }
189         else
190         {
191             break;
192         }
193     }
194     ++closeListCount;
195 }
196 
197 //把开启列表中的当前节点删除
198 void outOpenList()
199 {
200     --openListCount;
201 
202     OpenList[0]=OpenList[openListCount];
203     struct baseNode temp;
204 
205     for (int i = 0,p=0; 2*i+1<openListCount;i=p)
206     {
207         if (2*i+2>openListCount-1)
208         {
209             p = 2 * i + 1;
210         }
211         else
212         {
213             if (OpenList[2 * i + 1].f<OpenList[2 * i + 2].f)
214             {
215                 p = 2 * i + 1;
216             }
217             else
218             {
219                 p = 2 * i + 2;
220             }
221         }
222 
223         if (OpenList[p].f<OpenList[i].f)
224         {
225             temp=OpenList[p];
226             OpenList[p]=OpenList[i];
227             OpenList[i] = temp;
228         }
229         else
230         {
231             break;
232         }
233     }
234 }
235 
236 //删除开启列表中指定的元素,重构最小二叉堆
237 //(注:这个可以用很多方法实现,示例并非最优)
238 void outOpenList2(struct baseNode iter)
239 {
240     int number=openListCount-1;
241     struct baseNode openlist2[MAX_number*MAX_number];
242     for (int i = 0; i < openListCount; ++i)
243     {
244         if (OpenList[i].i==iter.i&&OpenList[i].j==iter.j)
245         {
246             continue;
247         }
248         openlist2[i]=OpenList[i];
249     }
250 
251     openListCount = 0;
252     for (int i = 0; i < number; ++i)
253     {
254         putInOpenList(openlist2[i]);
255     }
256 }
257 
258 //对于一路上的每个点,分析它的最多八个邻居,并加入邻居列表
259 void addNeibo(struct baseNode iter)
260 {
261     neibNum = 0;
262 
263     for (int i = iter.i - 1; i <= iter.i + 1; ++i)
264     {
265         for (int j = iter.j - 1; j <= iter.j + 1; ++j)
266         {
267             if (i >= 0 && i <= MAX_number - 1 && j >= 0 && j <= MAX_number - 1)
268             {
269                 if (i == iter.i&&j == iter.j)
270                 {
271                 }
272                 else
273                 {
274                     map[i][j].h = manhatten(i, j);
275 
276                     Neibo[neibNum] = map[i][j];
277                     ++neibNum;
278                 }
279             }
280         }
281     }
282 }
283 
284 //查看临近格在不在开启列表中的函数
285 int isInOpenList(struct baseNode neibo)
286 {
287     for (int i = 0; i < openListCount - 1; ++i)
288     {
289         if (OpenList[i].i == neibo.i&&OpenList[i].j == neibo.j)
290         {
291             return 1;
292         }
293     }
294     return 0;
295 }
296 
297 //查看指定的temp在不在关闭列表中的函数
298 int isInCloseList(struct baseNode temp)
299 {
300     int low = 0, high = closeListCount - 1, mid = (low + high) / 2;
301 
302     for (; low<=high; mid = (low + high) / 2)
303     {
304         if ((CloseList[mid].i*MAX_number + CloseList[mid].j + 1)==(temp.i*MAX_number + temp.j + 1))
305         {
306             return 1;
307         }
308         else if((CloseList[mid].i*MAX_number + CloseList[mid].j + 1) > (temp.i*MAX_number + temp.j + 1))
309         {
310             high = mid - 1;
311         }
312         else
313         {
314             low = mid + 1;
315         }
316     }
317     return 0;
318 }
319 
320 //A*中的启发式函数,用于求指定位置和终点之间的曼哈顿距离
321 int manhatten(int i, int j)
322 {
323     int a= (abs(AsceneryList[1].node.i - i) + abs(AsceneryList[1].node.j - j));
324     if (a==0)
325     {
326         FLAG = 1;
327     }
328 
329     return a*10;
330 }
331 
332 //求当前点与父亲节点的距离
333 int increment(struct baseNode this)
334 {
335     if ((abs(this.father->i-this.i)==1) && (abs(this.father->j - this.j) == 1))
336     {
337         return 14*this.weigt;
338     }
339     else if ((this.father->i - this.i) == 0 && (this.father->j - this.j) == 0)
340     {
341         return 0;
342     }
343     else
344     {
345         return 10*this.weigt;
346     }
347 }
348 
349 //求出用当前点作为父节点时这个点的G值
350 int NewG(struct baseNode this,struct baseNode father)
351 {
352     if (abs(father.i - this.i) == 1 && abs(father.j - this.j) == 1)
353     {
354         return father.g+14;
355     }
356     else if (abs(father.i - this.i) == 0 && abs(father.j - this.j) == 0)
357     {
358         return father.g;
359     }
360     else
361     {
362         return father.g+10;
363     }
364 }
365 
366 //把A*算法的节点按倒序整理到Astack里面
367 void arrange(struct baseNode iter)
368 {
369     AstackCount = 0;
370     for (; ; iter=map[iter.father->i][iter.father->j])
371     {
372         Astack[AstackCount] = iter;
373         ++AstackCount;
374         if (iter.i == AsceneryList[0].node.i&&iter.j == AsceneryList[0].node.j)
375         {
376             break;
377         }
378     }
379 }
380 
381 //打印出A*算法的路径矩阵
382 printAstar()
383 {
384     printf("A为最佳路径,Q为不经过区域\n\n");
385     int boole = 0;
386 
387     for (int i = 0; i < MAX_number; ++i)
388     {
389         for (int j = 0; j < MAX_number; ++j)
390         {
391             for (int w=0; w<AstackCount; ++w)
392             {
393                 if (Astack[w].i==i&&Astack[w].j==j)
394                 {
395                     boole = 1;
396                     break;
397                 }
398             }
399 
400             if (boole==1)
401             {
402                 printf("A ");
403                 boole = 0;
404             }
405             else
406             {
407                 printf("Q ");
408             }
409         }
410         printf("\n");
411     }
412 }
413 
414 //Astar的本体
415 void Astar()
416 {
417     FLAG=0;
418     //每次执行A*算法,都初始化开启/关闭列表
419     openListCount = 0;
420     closeListCount = 0;
421 
422     //创建一个迭代器,每次都等于f值最小的节点
423     struct baseNode iter;
424 
425     //让这个迭代器的初值为起点
426     iter.i = AsceneryList[0].node.i;
427     iter.j = AsceneryList[0].node.j;
428     iter.weigt = map[AsceneryList[0].node.i][AsceneryList[0].node.j].weigt;
429 
430     //起点的没有父节点,且为唯一G值为0的点
431     iter.g = 0;
432     iter.h = manhatten(iter.i,iter.j);
433     iter.f = iter.g + iter.h;
434 
435     //创建终点
436     struct baseNode ender;
437 
438     ender.i = AsceneryList[1].node.i;
439     ender.j = AsceneryList[1].node.j;
440 
441     //把起点放入开启列表
442     putInOpenList(iter);
443 
444     //当开启列表为空或者终点在关闭列表中,结束寻径
445     for (;  openListCount != 0 && FLAG==0;)
446     {
447         //取出开启列表中f值最小的节点(之一),并设为iter(当前点)
448         iter = readTopOpenList();
449 
450         //把最小点从开启列表中删除
451         outOpenList();
452 
453         //把当前点记录在关闭列表中
454         putInCloseList(iter);
455 
456         //把当前点的邻居加入邻居列表
457         addNeibo(iter);
458 
459         //对于每个邻居,分三种情况进行操作
460         for (int i = 0; i < neibNum; ++i)
461         {
462             //如果这个邻居节点不可通过,或者这个邻居节点在关闭列表中,略过它
463             if (Neibo[i].weigt==0 || isInCloseList(Neibo[i]))
464             {
465             }
466             //如果这个邻居节点已经在开启列表中
467             else if(isInOpenList(Neibo[i]))
468             {
469                 if (NewG(Neibo[i],iter)<Neibo[i].g)
470                 {
471                     map[Neibo[i].i][Neibo[i].j].father = &map[iter.i][iter.j];
472                     map[Neibo[i].i][Neibo[i].j].g = map[iter.i][iter.j].g + increment(Neibo[i]);
473                     map[Neibo[i].i][Neibo[i].j].f = map[Neibo[i].i][Neibo[i].j].g + map[Neibo[i].i][Neibo[i].j].h;
474 
475                     outOpenList2(Neibo[i]);
476                     putInOpenList(Neibo[i]);
477                 }
478             }
479             //如果这个邻居节点不在开启列表中
480             else
481             {
482                 map[Neibo[i].i][Neibo[i].j].father= Neibo[i].father = &map[iter.i][iter.j];
483                 map[Neibo[i].i][Neibo[i].j].g = map[iter.i][iter.j].g + increment(Neibo[i]);
484                 map[Neibo[i].i][Neibo[i].j].f = map[Neibo[i].i][Neibo[i].j].g + map[Neibo[i].i][Neibo[i].j].h;
485 
486                 Neibo[i] = map[Neibo[i].i][Neibo[i].j];
487                 putInOpenList(Neibo[i]);
488             }
489         }
490     }
491 
492     arrange(map[ender.i][ender.j]);
493     printAstar();
494 }
func.h

      在下一章里,我们将尝试用其他的方式存储地图并且用新的方式写启发函数,敬请期待。

A*寻路算法的探寻与改良(三)

标签:

原文地址:http://www.cnblogs.com/bugrabbit/p/5052164.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!