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

!!(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
#include
#define MAX 500
static 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].fh_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








你可能感兴趣的:(经典算法,数据结构)