频道栏目
首页 > 资讯 > 其他综合 > 正文

人工智能A*算法C实现

17-06-22        来源:[db:作者]  
收藏   我要投稿

实验前,其实是想创建三个文件,如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 
#include 
#include 
#include 
#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 );
    while ( CLOSED[i].name != 0 && CLOSED[i].name != a.name )
        i++;
    if ( CLOSED[i+1].name == 0 )
        {
            CLOSED[i].name = 0, CLOSED[i].HN = 0, CLOSED[i].GN = 0, CLOSED[i].FN = 0;
            return 1;
        }
    else
    {
        for ( k = i; CLOSED[k].name !=0; k++ ) // the total of nodes in OPEN
            ;
        for ( j = k-1; j > i; j-- ) // assignment
             CLOSED[j-1].name = CLOSED[j].name, CLOSED[j-1].FN = CLOSED[j].FN,
                      CLOSED[j-1].GN = CLOSED[j].GN, CLOSED[j-1].HN = CLOSED[j].HN;
        CLOSED[k-1].name = 0, CLOSED[k-1].HN = 0, CLOSED[k-1].GN = 0, CLOSED[k-1].FN = 0;
    }
    return 1;
}
// put node n into CLOSED list
int PutIntoClosed ( struct Node a, struct Node * CLOSED)
{
    int i = 0;
    printf( "Put %c into CLOSED list.\n", a.name);
    while ( CLOSED[i].name != 0 )
        i++;
    CLOSED[i].name = a.name, CLOSED[i].HN = a.HN,
              CLOSED[i].GN = a.GN, CLOSED[i].FN = a.FN;
    return 1;
}
// put node into the OPEN list
int PutIntoOpen ( struct Node a, struct Node * OPEN )
{
    int i = 0;
    printf( "Put %c into OPEN list.\n", a.name);
    while ( OPEN[i].name != 0 )
        i++;
    OPEN[i].name = a.name, OPEN[i].HN = a.HN,
            OPEN[i].GN = a.GN, OPEN[i].FN = a.FN;
    return 1;
}
// remove node n form CLOSED list

// calculate the fn of successors and update both lists
int CalSucc ( struct Node * a, struct Node * OPEN, struct Node * CLOSED,
              struct Edge * TotEdge, struct Node * NodeArr )
{
    // j refers to the number of edges in Tempedge
    int i, j;
    // store the successors 4 in max
    struct Edge * TempEdge = (struct Edge *)malloc( MaxNodeNum * sizeof(struct Edge));
    if ( TempEdge == NULL )
        printf ( "Error allocating memory!\n");
    memset( TempEdge, 0, MaxNodeNum * sizeof(struct Edge));
    // Temp edge
    struct Edge * Temp = (struct Edge *)malloc(sizeof(struct Edge));
    if ( Temp == NULL)
        printf ( "Error allocating memory!\n");
    // Temp node
    struct Node * TempNode = (struct Node *)malloc(sizeof(struct Node));
    if ( TempNode == NULL )
        printf ( "Error allocating memory!\n");
    // traverse the edge array and find the successors
    for ( i = 0, j = 0; i < EdgeNum; i++ )
    {
        // read from the edge array
        Temp->FirstNode = TotEdge[i].FirstNode, Temp->SecondNode = TotEdge[i].SecondNode,
              Temp->Successor = TotEdge[i].Successor, Temp->Weight = TotEdge[i].Weight;
        // find the successors of node a(n)
        if ( Temp->FirstNode == a->name || Temp->SecondNode == a->name )
        {
            // store the edge into the tempedge
            TempEdge[j].FirstNode = Temp->FirstNode;
            TempEdge[j].SecondNode = Temp->SecondNode;
            TempEdge[j].Weight = Temp->Weight;
            if ( TempEdge[j].FirstNode == a->name )
                TempEdge[j].Successor = TempEdge[j].SecondNode;
            else
                TempEdge[j].Successor = TempEdge[j].FirstNode;
            j++;
        }

    }
    // for each successor renew the pointers
    for ( i = 0; i < MaxNodeNum && TempEdge[i].Weight != 0; i++ )
    {
        bool InOpen = 0, InClosed = 0;
        int k;
        // traverse the OPEN lists to find the successor node
        for ( k = 0; k < NodeNum && OPEN[k].name != 0; k++ )
            if( OPEN[k].name == TempEdge[i].Successor )
                InOpen = 1;
        for ( k = 0; k < NodeNum && CLOSED[k].name != 0; k++ )
            if( CLOSED[k].name == TempEdge[i].Successor )
                InClosed = 1;

        // find the successor's corresponding node
        for ( k = 0; k < NodeNum; k++ )
            if ( NodeArr[k].name == TempEdge[i].Successor )
                break;
        // calculate the value and insert into OPEN list
        TempNode->name = NodeArr[k].name;
        TempNode->HN = NodeArr[k].HN;
        TempNode->GN = TempEdge[i].Weight;
        TempNode->FN = TempNode->HN + TempNode->GN;
        // if the successor does not contain in OPEN and CLOSED list
        if ( !InOpen && !InClosed )
            PutIntoOpen( *TempNode, OPEN );
        // if the successor is in OPEN but not in CLOSED
        else if ( InOpen && !InClosed )
            if ( TempNode->FN < NodeArr[j].FN )
                NodeArr[j].FN = TempNode[j].FN;
            else
                ;
        // if the successor is in CLOSED but not in OPEN
        else if ( !InOpen && InClosed )
        {
            // remove the node from the CLOSED and put it into the OPEN list
            if ( TempNode->FN < NodeArr[j].FN )
            {    NodeArr[j].FN = TempNode[j].FN;
                ReFromClosed( NodeArr[j], CLOSED );
                PutIntoOpen( NodeArr[j], OPEN);
            }
            else
                ;
        }
    }
    free ( TempEdge ), free ( Temp ), free ( TempNode );
    return 1;
}

// sort the nodes of OPEN list
int SortNodes ( struct Node * OPEN )
{
    int i, j, number;
    struct Node * location = ( struct Node *)malloc( sizeof( struct Node ));
    if ( location == NULL )
        printf ( "Error allocating memory!\n");
    struct Node * temp = ( struct Node *)malloc( sizeof( struct Node ));
    if ( temp == NULL )
        printf ( "Error allocating memory!\n");
    location = OPEN;
    for ( number = 0; OPEN[number].name != 0; number++ )
        ;
    OPEN = location;
    // here use the insertion sort
    for ( i = 1; i < number && OPEN[i].name != 0; i++ )
    {

        for ( j = i - 1; j >= 0 && OPEN[j].FN > OPEN[j+1].FN; j-- )
        {
            temp->name = OPEN[j+1].name, temp->FN = OPEN[j+1].FN,
                  temp->GN = OPEN[j+1].GN, temp->HN = OPEN[j+1].HN;
            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[j].name = temp->name, OPEN[j].FN = temp->FN,
                    OPEN[j].GN = temp->GN, OPEN[j].HN = temp->HN;
        }
    }
    free( temp );
    return 1;
}

int main(void)
{
    int i = 0; // the counter of the result path
    struct Edge TotalEdge[EdgeNum] =
    {
        { 3, 'A', 'B', 0}, { 4, 'B', 'C', 0}, { 8, 'C', 'D', 0}, { 2, 'D', 'E', 0},
        { 4, 'A', 'H', 0}, { 2, 'G', 'H', 0}, { 4, 'F', 'G', 0}, { 3, 'D', 'F', 0},
        { 5, 'B', 'H', 0}, { 3, 'C', 'G', 0}, { 8, 'D', 'G', 0}
    };

    struct Node NodeArr[NodeNum] =
    {
        { 'A', 15, 0, 0 }, { 'B', 14, 0, 0 }, { 'C', 10, 0, 0 }, { 'D', 2, 0, 0 }, { 'E', 2, 0, 0 },
        { 'F', 5, 0, 0 },  { 'G', 9, 0, 0 },  { 'H', 11, 0, 0 }
    };
    // store the result path
    char ResPath[NodeNum] = { 0, 0, 0, 0, 0, 0, 0, 0};
    // open list 11 elements
    struct Node * OPEN= (struct Node *)malloc(EdgeNum * sizeof(struct Node));
    if ( OPEN == NULL )
        printf ( "Error allocating memory!\n");
    memset( OPEN, 0, EdgeNum * sizeof(struct Node) );
    // closed list 11 elements
    struct Node * CLOSED = (struct Node *)malloc(EdgeNum * sizeof(struct Node));
    if ( CLOSED == NULL)
        printf ( "Error allocating memory!\n");
    memset( CLOSED, 0, EdgeNum * sizeof(struct Node) );
    // node n
    struct Node * n = (struct Node *)malloc(sizeof(struct Node));
    if ( n == NULL )
        printf ( "Error allocating memory!\n");
// The A* algorithm:
// OPEN CLOSED list both initialized to 0
    OPEN[0].name = NodeArr[0].name, OPEN[0].FN = NodeArr[0].FN,
            OPEN[0].GN = NodeArr[0].GN, OPEN[0].HN = NodeArr[0].HN;   // node A
    // 将初始节点放入OPEN表
    if ( OPEN[0].name == 0 ) return -1; // error
    while ( OPEN[0].name ) // OPEN 表非空
    {
        n->name = OPEN[0].name, n->FN = OPEN[0].FN,
           n->GN = OPEN[0].GN,n->HN = OPEN[0].HN; // pointer assignment
        ResPath[i++] = n->name; // store the nodes
        printf( "\nn = %c, fn = %d, gn = %d, hn = %d\n", n->name, n->FN, n->GN, n->HN );
        if ( n->name == 'E')
        {
            printf( "\n");
            printf ( "The result path:\n");
            for ( i = 0; ResPath[i] != 0; i++ )
                printf ( "%c ", ResPath[i]);
            free( OPEN ),free( CLOSED ),free ( n );
            return 0;
        } // if GOAL(n) EXIT(success) 取得n节点,为目标节点则返回成功
        else                          // REMOVE(n, OPEN), ADD(n,CLOSED)
        {
            // calculate the value
            //n->GN = 0,n->FN = n->GN + n->HN;
            // 对于n的每个子节点
            if ( ReFromOpen( *n, OPEN ) )
                ;
            else
                printf ( "Error!\n");
            if (CalSucc ( n, OPEN, CLOSED, TotalEdge, NodeArr ))
                ;
            else
                printf ("Error!\n");
            if ( PutIntoClosed( *n, CLOSED ) )
                ;
            else
                printf( "Error!\n");
            if ( SortNodes ( OPEN ) )
                ;
            else
                printf( "Error!\n");
        }
    }
    return -1;
}
相关TAG标签
上一篇:MySQL数据库基础知识日常练习
下一篇:linux之vim配置及使用示例
相关文章
图文推荐

关于我们 | 联系我们 | 广告服务 | 投资合作 | 版权申明 | 在线帮助 | 网站地图 | 作品发布 | Vip技术培训 | 举报中心

版权所有: 红黑联盟--致力于做实用的IT技术学习网站