最短路径 A*算法 应用堆优化

来源:互联网 发布:java ajax文件上传 编辑:程序博客网 时间:2024/06/05 23:53

!!(5月27日)发现一个很牛的东东,可以加深理解A* http://qiao.github.io/PathFinding.js/visual/ 


去年的这个时候和同学一起玩code vs asia的比赛学会了A*算法

当初在数据结构算法什么都不懂的情况下,我们能写出A*算法已经感觉非常满足了

当初用java进行实现的,那个时候脑袋里就只想着能实现就好,于是那个神奇的A*就被我们迷迷糊糊的写出来了

下面就想着高兴呢,也没仔细想过整体的流程,那里可以有优化的地方。虽然整体实现了,但是细节方面简直是令人发指

时隔一年,玩acm再次碰到了那个相似的使用A*算法的情况。于是凭借着我寥寥无几的数据结构知识外加蹩脚的c,c++语言使用

写出了一个自我感觉比以前java实现的优化了那么一点点的A*算法

接下来正题:

如果你清楚A*算法但是不知道怎么实现,我这里可能稍微给你一点帮助

如果你不清楚A*算法,可以先去学一下,网络上有很多比较好的文章,这里我就不多做讲解了


A*堆优化方式:A*算法利用了一个估价函数,计算图上节点的时候,对节点进行了整体的估价

                          然后选出最优的节点进行访问,以此类推...

既然是选择最优的节点,那么我们就可以实现一个优先队列。来方便我们取出最优的节点。所以使用堆就成了我们优化的不二选择

把能访问的节点加入我们的开放队列(堆形式),取出F最小的节点,然后访问与这个节点相连的节点,并且把满足条件能访问的加入

开放列表,如果满足条件并且已经加入到开放列表中了,那么就比较其G值。选取比较小的,然后更新开放列表中的节点。

(这里,在使用以维护F的最小值为条件的堆中,我们无法快速判断一个节点是否已经存在于堆中。所以我想到了另外再构建一个hash图

维护原图的每一个节点在堆中的位置,这样就能使用hash图直接的判断原图中的节点是否已经存在于堆中。维护hash图,需要和维护堆进行同步

所以每次加入一个节点时维护hash图的复杂度为logN,同维护堆的logN,并且在判断的时候是O(1)的时间复杂度,但构建hash图又增加了空间复杂度)

(优化好处,比A*算法使用普通链表形式进行维护的开放列表时间复杂度上好很多,普通链表取最小值,打擂台形式,时间复杂度O(N),插入的时候

判断有没有已经被插入也是O(N),所以比较时间复杂度优点显而易见)


下面是我憋脚的实现。

测试的图为二维的平面图,可以上下左右,四个方向行走,也可以八个方向行走(八个方向少考虑一个问题),图上0表示可以走,1表示不通。

八方向少考虑的问题是:如果图为00  那么我能否从(1,1)直接走到(2,2)也就是斜角过能否“蹩马脚”

                                                     10

额,打字好累直接贴代码好了

#include<stdio.h>#include<stdlib.h>#define MAX 500static int DX[8]= {-1,0,1,0,1,-1,1,-1};static int DY[8]= {0,1,0,-1,1,1,-1,-1};int grap[MAX][MAX];int hash[MAX][MAX];int n,m;struct Node {    int x,y,g,h,f;};Node heap[MAX*MAX];int h_end=0;int insert(Node n);//堆中插入节点int update(int idx,Node n);//向上更新堆中的节点Node getMin();//取出堆中的最小值void swap(int idx1,int idx2);//交换hash数组对应堆中节点的位置,并交换堆中的节点void add_open(int x,int y,int g,Node e,int dir);//把图上的节点添加进开放列表void add_close(Node n);//把图上的节点添加进关闭列表void aStar(Node s,Node e,int dir);//主要算法int insert(Node n) {    return update(++h_end,n);}int update(int idx,Node n) {    int e=idx,p;    heap[e]=n;    while(e>1) {        p=e>>1;        if(heap[e].f<heap[p].f) {            swap(e,p);            e=p;        } else break;    }    return e;}Node getMin() {    int ls,rs,rt=1;    Node res=heap[rt];    heap[rt]=heap[h_end--];    while(1) {        ls=rt<<1;        rs=rt<<1|1;        if(ls>h_end||rs>h_end) {            if(ls<=h_end&&heap[rt].f>heap[ls].f)swap(rt,ls);            break;        }        if(heap[rt].f<=heap[ls].f&&heap[rt].f<=heap[rs].f)break;        if(heap[rt].f>heap[ls].f&&heap[rs].f>=heap[ls].f) {            swap(rt,ls);            rt=ls;        } else {            swap(rt,rs);            rt=rs;        }    }    return res;}void swap(int idx1,int idx2) {    hash[heap[idx1].x][heap[idx1].y]=idx2;    hash[heap[idx2].x][heap[idx2].y]=idx1;    Node tmp=heap[idx1];    heap[idx1]=heap[idx2];    heap[idx2]=tmp;}void add_open(int x,int y,int g,Node e,int dir) {    if(x<0||x>=n)return;    if(y<0||y>=m)return;    if(grap[x][y]!=0||hash[x][y]==-1)return;    Node tmp;    tmp.x=x;tmp.y=y;    int h;    if(dir<4) {        g=g+10;        h=(abs(e.x-x)+abs(e.y-y))*10;    } else {        g=g+14;        h=(abs(e.x-x)+abs(e.y-y))*10;    }    tmp.g=g;    tmp.h=h;    tmp.f=g+h;    if(hash[x][y]!=0) {        if(heap[hash[x][y]].g>g) {            update(hash[x][y],tmp);        }    } else {        hash[x][y]=insert(tmp);    }}void add_close(Node n) {    hash[n.x][n.y]=0;    grap[n.x][n.y]=88;}void aStar(Node s,Node e,int dir) {    hash[s.x][s.y]=insert(s);    Node tmp;    int x,y,g,i;    while(h_end>0) {        tmp=getMin();        add_close(tmp);        if(tmp.x==e.x&&tmp.y==e.y) {            printf("%d\n",tmp.g);            break;        }        for(i=0; i<dir; i++) {            x=tmp.x+DX[i];            y=tmp.y+DY[i];            g=tmp.g;            add_open(x,y,g,e,i);        }    }}int main() {    freopen("nput.txt","r",stdin);    int x1,y1,x2,y2,i,j;    scanf("%d%d",&n,&m);    for(i=0; i<n; i++) {        for(j=0; j<m; j++) {            scanf("%d",&grap[i][j]);        }    }    scanf("%d%d%d%d",&x1,&y1,&x2,&y2);    Node star,end;    star.x=x1-1;star.y=y1-1;star.g=0;    end.x=x2-1;end.y=y2-1;end.g=0;    aStar(star,end,4);    for(i=0; i<n; i++) {        for(j=0; j<m; j++) {            printf("%2d ",grap[i][j]);        }        printf("\n");    }    return 0;}








原创粉丝点击