实验前,其实是想创建三个文件,如C++ primer plus中的,一个头文件,一个函数的实现文件,一个是具体使用的文件,但这样有点问题没解决,只好都放在一个文件当中。
一、实验内容
对下图所示的状态空间图用A*算法进行搜索:
其中A为起始节点,E为目标节点,各节点的启发值表示在括号内。
二、实验设计(原理分析及流程)
A* 是启发式搜索算法。该算法创建两个表:OPEN(类似于回溯算法中的NSL,它列出已经产生但其孩子还未被分析的状态)和CLOSED(记录已经分析了的状态,为回溯算法中的DE与SL列表的联合)。
算法预先将初始节点放入OPEN表,从初始节点开始分析,若该节点是目标节点,则成功并返回.否则,分析初始节点的每个子节点,通过比较它们的F(n)函数值以及是否在OPEN,CLOSED表中来进行节点在这两个表的移动,之后对OPEN表中的子节点按F(n)大小进行排序,下一次循环选取OPEN表的第一个节点进行分析,直到最后选取到目标节点结束算法.
算法以每次循环从OPEN表中选取的节点为目标路径的节点,我将它们用一个静态数组存储起来,最后打印数组中的节点得到答案.
我的算法使用了两个结构体,分别代表节点,其成员包括:名字,FN,GN,HN;边,其成员包括:第一个节点,第二个节点,后继结点,权重。
使用六个函数,其中两个为节点进出OPEN表,两个为节点进出CLOSED表,一个为分析选取节点的后继结点的函数,还有一个使用插入排序对OPEN表的节点进行排序。
伪代码:
Best_First_Search()
{
Open = [起始节点]; Closed = [];
while ( Open表非空 )
{
从Open中取得一个节点X,并从OPEN表中删除。
if (X是目标节点)
{
求得路径PATH;返回路径PATH;
}
for (每一个X的子节点Y)
{
if( Y不在OPEN表和CLOSE表中 )
{
求Y的估价值;并将Y插入OPEN表中;//还没有排序
}
else
if( Y在OPEN表中 )
{
if( Y的估价值小于OPEN表的估价值 )
更新OPEN表中的估价值;
}
else //Y在CLOSE表中
{
if( Y的估价值小于CLOSE表的估价值 )
{
更新CLOSE表中的估价值;
从CLOSE表中移出节点,并放入OPEN表中;
}
}
将X节点插入CLOSE表中;
按照估价值将OPEN表中的节点排序;
}//end for
}//end while
}//end func
代码:
// A*算法实现
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <stdbool.h>
#define NodeNum 8
#define EdgeNum 11
#define MaxNodeNum 4
// edges and nodes structures
struct Edge
{
int Weight;
char FirstNode;
char SecondNode;
char Successor;
};
struct Node
{
char name;
int HN;
int GN;
int FN;
//struct Edge LEdge[];
};
int ReFromOpen ( struct Node a, struct Node * OPEN )
{
int i = 0, j, k;
printf ( "Remove %c from the OPEN list!\n", OPEN->name );
while ( OPEN[i].name != 0 && OPEN[i].name != a.name )
i++;
if ( OPEN[i+1].name == 0 )
{
OPEN[i].name = 0, OPEN[i].HN = 0, OPEN[i].GN = 0, OPEN[i].FN = 0;
return 1;
}
else
{
for ( k = i; OPEN[k].name !=0; k++ ) // the total of nodes in OPEN
;
for ( j = k-1; j > i; j-- ) // assignment
OPEN[j-1].name = OPEN[j].name, OPEN[j-1].FN = OPEN[j].FN,
OPEN[j-1].GN = OPEN[j].GN, OPEN[j-1].HN = OPEN[j].HN;
OPEN[k-1].name = 0, OPEN[k-1].HN = 0, OPEN[k-1].GN = 0, OPEN[k-1].FN = 0;
}
return 1;
}
int ReFromClosed ( struct Node a, struct Node * CLOSED )
{
int i = 0, j, k;
printf ( "Remove %c from the CLOSED list!\n", CLOSED->name );