【发布时间】:2014-12-15 23:08:03
【问题描述】:
我正在为使用图形的“隐式”表示的课程编写“游戏”项目:我有一个 N*M 项的矩阵,定义如下:。
typedef struct {
int x;
int y;
int k; //value of the position
int ID;
bool path; //temporary field used to print the path
} VCOORD;
typedef struct gObj {
//numero vertici
int vNum; //number of vertices
VCOORD ** maze; //pointer to implicit maze
int width; //width of the maze
int height; //height of the maze
//function pointers
struct gObj * ( *build) ( struct gObj *, int );
Set * ( *getAdjList ) ( struct gObj *graph, int u );
void ( *insertEdge ) ( struct gObj *, int , int , int );
void ( *insertVertex ) ( struct gObj *graph );
int ( *getWeight ) ( struct gObj *, int, int );
int ( *transpose ) ( struct gObj *graph );
int * ( *path) ( struct gObj *, int , int );
} GRAPHOBJ;
我已经实现了:
BFS、Dijkstra、A*
BFS 和 Dijkstra 工作正常,但我对 A* 有一些问题
A*(一颗星)
int *a_star ( GRAPHOBJ *graph, int s, int t ) {
int x, y, i;
int cost;
bool found = false;
void * tmp; //used to store Heap first element
Set * AdjList = NULL; //Adjiacence list implemented as queue
Set * closed = NULL; //Closed set implemented as queue
Heap * open = NULL; //Open set implemented as Heap
int * pred = ( int *) malloc ( graph->vNum * sizeof ( int ) );
int g[graph->vNum]; //g distance function
int f[graph->vNum]; //f distance function
//initialization
for ( i = 0; i < graph->vNum; i++ ) {
f[i] = INFINITE;
g[i] = 0;
pred[i] = NIL;
}
f[s] = heuristic ( graph, s, t );
open = initializeHeap ( minHeapify );
insert ( open, new_HeapData ( s, 0 ) );
while ( !isHeapEmpty ( open ) && found == false ) {
//extracting the first Object of the Heap ( Open )
tmp = extractFirst ( open );
//pushing the node into the Closed set
push ( closed , setInt ( x ) );
//get the int number from the extracted Object
x = getData ( tmp );
//get the ditance f from the extracted Object
f[x] = getKey ( tmp );
//debug
if ( PRINTALL ) graph->maze[getCoord ( graph, x )->y][getCoord ( graph, x )->x].path = true;
//printf ("x: %d ", x);
if ( x == t ) {
found = true;
} else {
AdjList = graph->getAdjList ( graph, x );
while ( !isEmpty ( AdjList ) ) {
//getting the first element of the adj. list
y = getInt ( getFront ( AdjList ) );
//graph->getWeight refers to getMatrixWeight
g[y] = g[x] + graph->getWeight ( graph, x, y );
cost = g[y] + heuristic ( graph, y, t );
//checking if y is in the open set
bool yInOpen = heapIntSearch ( open, y );
//checking if y is in the closed set
bool yInClosed = intSearch ( closed , y );
if ( yInOpen && cost < f[y] ) { // case 1
decreaseKey ( open, y, cost );
}
else if ( yInClosed && cost < f[y] ) { // case 2
deleteFromSet ( closed, y );
insert ( open, new_HeapData ( y, cost ) );
}
else if ( !yInClosed && !yInOpen ) { // case 3
insert ( open, new_HeapData ( y, cost ) );
}
AdjList = dequeue ( AdjList );
if ( pred[y] == NIL )
pred[y] = x;
}
}
}
pred[s] = NIL;
printf ("\n\n");
return pred;
}
启发式函数,欧几里得/曼哈顿距离:
int heuristic ( GRAPHOBJ *graph, int s, int t ) {
VCOORD * start = getCoord ( graph, s );
VCOORD * target = getCoord ( graph, t );
/*manhattan*/return ( abs ( start->x - target->x ) + abs ( start->y - target->y ) );
/*euclidian*///return pow ( pow ( ( target->x - start->x ), 2 ) + pow ( ( target->y - start->y ), 2 ), 0.5 );
}
边权重函数:
int getMatrixWeight ( GRAPHOBJ *graph, int u, int v ) {
int weight = 1;
return weight;
}
Adjiacence 列表实现(NORTH、SOUTH 等是减少/增加坐标的宏:
Set *getAdjList ( struct gObj *graph, int u ) {
Set *Adj = NULL;
int x = u % graph->width;
int y = u / graph->width;
int neighbor;
if ( NORTH(y) > 0 && graph->maze[NORTH(y)][x].k != 9 ) {
//if ( NORTH(y) > 0 ) {
neighbor = graph->width * ( NORTH(y) ) + ( x );
Adj = enqueue ( Adj, setInt ( neighbor ) );
}
if ( EAST(x) < graph->width && graph->maze[y][EAST(x)].k != 9 ) {
//if ( EAST(x) < graph->width ) {
neighbor = graph->width * ( y ) + ( EAST(x) );
Adj = enqueue ( Adj, setInt ( neighbor ) );
}
if ( SOUTH(y) < graph->height && graph->maze[SOUTH(y)][x].k != 9 ) {
//if ( SOUTH(y) < graph->height ) {
neighbor = graph->width * ( SOUTH(y) ) + ( x );
Adj = enqueue ( Adj, setInt ( neighbor ) );
}
if ( WEST(x) > 0 && graph->maze[y][WEST(x)].k != 9 ) {
//if ( WEST(x) > 0 ) {
neighbor = graph->width * ( y ) + ( WEST(x) );
Adj = enqueue ( Adj, setInt ( neighbor ) );
}
return Adj;
}
问题:
如果边的权重等于 1,正如在 getMatrixWeight 函数中声明的那样,A* 会采用奇怪的路径,例如:http://i.imgur.com/vbGNskF.png 如果边的权重 > 1,则 A* 正常工作(不是一直,而是 99%)
如果无法到达目标,A* 似乎会进入循环。 BFS 和 Dijkstra 没问题。
我实现了一个小“实用程序”来监控脚本的性能。 BFS 和 Dijkstra 工作正常(BFS 比 Dijkstra 快一点,但它可能取决于堆实现,我认为)。 但从图中可以看出,A* 似乎慢了 10 到 30 倍!所以我认为实现有问题,但我找不到问题所在(可能与第2点:循环有关)!
我认为其他功能(集合和堆实现、邻居实现)工作正常,因为 BFS 和 Dijkstra 没有问题。
如果您想查看其余代码,请点击此处:repo:https://bitbucket.org/ozeta86/labirinto/src
【问题讨论】:
标签: c performance dictionary graph a-star