starfish,问个问题

anjun 2001-08-13 12:56:15
传统的B+树会浪费很多指针域,有什么好的办法吗?
...全文
210 14 打赏 收藏 转发到动态 举报
写回复
用AI写文章
14 条回复
切换为时间正序
请发表友善的回复…
发表回复
anjun 2001-08-30
  • 打赏
  • 举报
回复
up
starfish 2001-08-22
  • 打赏
  • 举报
回复
A*算法我这里正好有一篇文章:


初识A*算法
A*算法在人工智能中是一种典型的启发式搜索算法,为了说清楚A*算法,我看还是先说说何谓启发式算法。

一、何谓启发式搜索算法:

在说它之前先提提状态空间搜索。状态空间搜索,如果按专业点的说法就是将问题求解过程表现为从 初始状态到目标状态寻找这个路径的过程。通俗点说,就是在解一个问题时,找到一条解题的过程可以从 求解的开始到问题的结果(好象并不通俗哦)。由于求解问题的过程中分枝有很多,主要是求解过程中求 解条件的不确定性,不完备性造成的,使得求解的路径很多这就构成了一个图,我们说这个图就是状态空 间。问题的求解实际上就是在这个图中找到一条路径可以从开始到结果。这个寻找的过程就是状态空间搜 索。

常用的状态空间搜索有深度优先和广度优先。广度优先是从初始状态一层一层向下找,直到找到目标 为止。深度优先是按照一定的顺序前查找完一个分支,再查找另一个分支,以至找到目标为止。这两种算 法在数据结构书中都有描述,可以参看这些书得到更详细的解释。

前面说的广度和深度优先搜索有一个很大的缺陷就是他们都是在一个给定的状态空间中穷举。这在状 态空间不大的情况下是很合适的算法,可是当状态空间十分大,且不预测的情况下就不可取了。他的效率 实在太低,甚至不可完成。在这里就要用到启发式搜索了。

启发式搜索就是在状态空间中的搜索对每一个搜索的位置进行评估,得到最好的位置,再从这个位置 进行搜索直到目标。这样可以省略大量无畏的搜索路径,提到了效率。在启发式搜索中,对位置的估价是 十分重要的。采用了不同的估价可以有不同的效果。我们先看看估价是如何表示的。

启发中的估价是用估价函数表示的,如:

f(n) = g(n) + h(n)

其中f(n) 是节点n的估价函数,g(n)实在状态空间中从初始节点到n节点的实际代价,h(n)是从n到目 标节点最佳路径的估计代价。在这里主要是h(n)体现了搜索的启发信息,因为g(n)是已知的。如果说详细 点,g(n)代表了搜索的广度的优先趋势。但是当h(n) >> g(n)时,可以省略g(n),而提高效率。这些就深了, 不懂也不影响啦!我们继续看看何谓A*算法。

二、初识A*算法:

启发式搜索其实有很多的算法,比如:局部择优搜索法、最好优先搜索法等等。当然A*也是。这些算法 都使用了启发函数,但在具体的选取 98e 最佳搜索节点时的策略不同。象局部择优搜索法,就是在搜索的过程中 选取“最佳节点”后舍弃其他的兄弟节点,父亲节点,而一直得搜索下去。这种搜索的结果很明显,由于舍 弃了其他的节点,可能也把最好的节点都舍弃了,因为求解的最佳节点只是在该阶段的最佳并不一定是全局 的最佳。最好优先就聪明多了,他在搜索时,便没有舍弃节点(除非该节点是死节点),在每一步的估价中 都把当前的节点和以前的节点的估价值比较得到一个“最佳的节点”。这样可以有效的防止“最佳节点”的 丢失。那么A*算法又是一种什么样的算法呢?其实A*算法也是一种最好优先的算法。只不过要加上一些约束 条件罢了。由于在一些问题求解时,我们希望能够求解出状态空间搜索的最短路径,也就是用最快的方法求 解问题,A*就是干这种事情的!我们先下个定义,如果一个估价函数可以找出最短的路径,我们称之为可采 纳性。A*算法是一个可采纳的最好优先算法。A*算法的估价函数克表示为:

f'(n) = g'(n) + h'(n)

这里,f'(n)是估价函数,g'(n)是起点到终点的最短路径值,h'(n)是n到目标的最断路经的启发值。由 于这个f'(n)其实是无法预先知道的,所以我们用前面的估价函数f(n)做近似。g(n)代替g'(n),但 g(n)>=g'(n) 才可(大多数情况下都是满足的,可以不用考虑),h(n)代替h'(n),但h(n)<=h'(n)才可(这一点特别的重 要)。可以证明应用这样的估价函数是可以找到最短路径的,也就是可采纳的。我们说应用这种估价函数的 最好优先算法就是A*算法。哈!你懂了吗?肯定没懂!接着看!

举一个例子,其实广度优先算法就是A*算法的特例。其中g(n)是节点所在的层数,h(n)=0,这种h(n)肯 定小于h'(n),所以由前述可知广度优先算法是一种可采纳的。实际也是。当然它是一种最臭的A*算法。

再说一个问题,就是有关h(n)启发函数的信息性。h(n)的信息性通俗点说其实就是在估计一个节点的值 时的约束条件,如果信息越多或约束条件越多则排除的节点就越多,估价函数越好或说这个算法越好。这就 是为什么广度优先算法的那么臭的原因了,谁叫它的h(n)=0,一点启发信息都没有。但在游戏开发中由于实 时性的问题,h(n)的信息越多,它的计算量就越大,耗费的时间就越多。就应该适当的减小h(n)的信息,即 减小约束条件。但算法的准确性就差了,这里就有一个平衡的问题。可难了,这就看你的了!

深入A*算法
----浅析A*算法在搜索最短路径中的应用
一、前言

在这里我将对A*算法的实际应用进行一定的探讨,并且举一个有关A*算法在最短路径搜索 的例子。值得注意的是这里并不对A*的基本的

概念作介绍,如果你还对A*算法不清楚的话, 请看姊妹篇《初识A*算法》。



二、A*算法的程序编写原理

我在《初识A*算法》中说过,A*算法是最好优先算法的一种。只是有一些约束条件而已。 我们先来看看最好优先算法是如何编写的吧。

如图有如下的状态空间:(起始位置是A,目标位置是P,字母后的数字表示节点的估价值)



搜索过程中设置两个表:OPEN和CLOSED。OPEN表保存了所有已生成而未考察的节点,CLOSED 表中记录已访问过的节点。算法中有一步是

根据估价函数重排OPEN表。这样循环中的每一 步只考虑OPEN表中状态最好的节点。具体搜索过程如下:


1)初始状态:
OPEN=[A5];CLOSED=[];
2)估算A5,取得搜有子节点,并放入OPEN表中;
OPEN=[B4,C4,D6];CLOSED=[A5]
3)估算B4,取得搜有子节点,并放入OPEN表中;
OPEN=[C4,E5,F5,D6];CLOSED=[B4,A5]
4)估算C4;取得搜有子节点,并放入OPEN表中;
OPEN=[H3,G4,E5,F5,D6];CLOSED=[C4,B4,A5]
5)估算H3,取得搜有子节点,并放入OPEN表中;
OPEN=[O2,P3,G4,E5,F5,
1000
D6];CLOSED=H3C4,B4,A5]
6)估算O2,取得搜有子节点,并放入OPEN表中;
OPEN=[P3,G4,E5,F5,D6];CLOSED=[O2,H3,C4,B4,A5]
7)估算P3,已得到解;

看了具体的过程,再看看伪程序吧。算法的伪程序如下:


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*算法的程序与此 是一样的,只要注意估价函数中的g(n)的h(n)约束条件就可以了。不清楚的可以看看《初识A*算法》。好了,我们可以进入另一个重要的话题,用A*算法实现最短路径的搜索。在此之 前你最好认真的理解前面的算法。不清楚可以找我。我的Email在文章尾。

三、用A*算法实现最短路径的搜索

在游戏设计中,经常要涉及到最短路径的搜索,现在一个比较好的方法就是用A*算法进行设 计。他的好处我们就不用管了,反正就是好!^_*

先复习一下,A*算法的核心是估价函数f(n),它包括g(n)和h(n)两部分。g(n) 是已经走过的 代价,h(n)是n到目标的估计代价。在这个例子中g(n)表示在状态空间从起始节点到 n节点的 深度,h(n)表示n节点所在地图的位置到目标位置的直线距离。啊!一个是状态空间,一个是 实际的地图,不要搞错了。再详细点说,有一个物体A,在地图上的坐标是(xa,ya),A所要到 达的目标b的坐标是(xb,yb)。则开始搜索时,设置一个起始节点1,生成八个子节点2 - 9 因 为有八个方向。如图:



仔细看看节点1、9、17的g(n)和h(n)是怎么计算的。现在应该知道了下面程序中的f(n)是如何 计算的吧。开始讲解源程序了。其实这个程序是一个很典型的教科书似的程序,也就是说只要 你看懂了上面的伪程序,这个程序是十分容易理解的。不过他和上面的伪程序有一些的不同, 我在后面会提出来。

先看搜索主函数:


void AstarPathfinder::FindPath(int sx, int sy, int dx, int dy)
{
NODE *Node, *BestNode;
int TileNumDest;
//得到目标位置,作判断用
TileNumDest = TileNum(sx, sy);
//生成Open和Closed表
OPEN=( NODE* )calloc(1,sizeof( NODE ));
CLOSED=( NODE* )calloc(1,sizeof( NODE ));
//生成起始节点,并放入Open表中
Node=( NODE* )calloc(1,sizeof( NODE ));
Node->g = 0;
//这是计算h值
Node->h = (dx-sx)*(dx-sx) + (dy-sy)*(dy-sy); // should really use sqrt().
//这是计算f值,即估价值
Node->f = Node->g+Node->h;
Node->NodeNum = TileNum(dx, dy);
Node->x = dx;
Node->y = dy;

OPEN->NextNode=Node; // make Open List point to first node
for (;;)
{ //从Open表中取得一个估价值最好的节点
BestNode=ReturnBestNode();
//如果该节点是目标节点就退出
if (BestNode->NodeNum == TileNumDest) // if we've found the end, break and fini
1000
sh
break;
//否则生成子节点
GenerateSuccessors(BestNode,sx,sy);
}
PATH = BestNode;
}

再看看生成子节点函数 GenerateSuccessors:


void AstarPathfinder::GenerateSuccessors(NODE *BestNode, int dx, int dy)
{
int x, y;
//哦!依次生成八个方向的子节点,简单!
// Upper-Left
if ( FreeTile(x=BestNode->x-TILESIZE, y=BestNode->y-TILESIZE) )
GenerateSucc(BestNode,x,y,dx,dy);
// Upper
if ( FreeTile(x=BestNode->x, y=BestNode->y-TILESIZE) )
GenerateSucc(BestNode,x,y,dx,dy);
// Upper-Right
if ( FreeTile(x=BestNode->x+TILESIZE, y=BestNode->y-TILESIZE) )
GenerateSucc(BestNode,x,y,dx,dy);
// Right
if ( FreeTile(x=BestNode->x+TILESIZE, y=BestNode->y) )
GenerateSucc(BestNode,x,y,dx,dy);
// Lower-Right
if ( FreeTile(x=BestNode->x+TILESIZE, y=BestNode->y+TILESIZE) )
GenerateSucc(BestNode,x,y,dx,dy);
// Lower
if ( FreeTile(x=BestNode->x, y=BestNode->y+TILESIZE) )
GenerateSucc(BestNode,x,y,dx,dy);
// Lower-Left
if ( FreeTile(x=BestNode->x-TILESIZE, y=BestNode->y+TILESIZE) )
GenerateSucc(BestNode,x,y,dx,dy);
// Left
if ( FreeTile(x=BestNode->x-TILESIZE, y=BestNode->y) )
GenerateSucc(BestNode,x,y,dx,dy);
}

看看最重要的函数GenerateSucc:


void AstarPathfinder::GenerateSucc(NODE *BestNode,int x, int y, int dx, int dy)
{
int g, TileNumS, c = 0;
NODE *Old, *Successor;
//计算子节点的 g 值
g = BestNode->g+1; // g(Successor)=g(BestNode)+cost of getting from BestNode to Successor
TileNumS = TileNum(x,y); // identification purposes
//子节点再Open表中吗?
if ( (Old=CheckOPEN(TileNumS)) != NULL ) // if equal to NULL then not in OPEN list, else it returns the Node in Old
{
//若在
for( c = 0; c <8; c++) if( BestNode->Child[c] == NULL ) // Add Old to the list of BestNode's Children (or Successors).
break;
BestNode->Child[c] = Old;
//比较Open表中的估价值和当前的估价值(只要比较g值就可以了)
if ( g g ) // if our new g value is Old's then reset Old's parent to point to BestNode { //当前的估价值小就更新Open表中的估价值 Old-Parent = BestNode;
Old->g = g;
Old->f = g + Old->h;
}
}
else //在Closed表中吗?
if ( (Old=CheckCLOSED(TileNumS)) != NULL ) // if equal to NULL then not in OPEN list, else it returns the Node in Old
{
//若在
for( c = 0; c<8; c++) if ( BestNode->Child[c] == NULL ) // Add Old to the list of BestNode's Children (or Successors).
break;
BestNode->Child[c] = Old;
//比较Closed表中的估价值和当前的估价值(只要比较g值就可以了)
if ( g g ) // if our new g value is Old's then reset Old's parent to point to BestNode { //当前的估价值小就更新Closed表中的估价值 Old-Parent = BestNode;
Old->g = g;
Old->f = g + Old->h;
//再依次更新Old的所有子节点的估价值
PropagateDown(Old); // Since we changed the g value of Old, we need
// to propagate this new value downwards, i.e.
// do a Depth-First traversal of the tree!
}
}
else//不在Open表中也不在Close表中
{
//生成新的节点
Successor = ( NODE* )calloc(1,sizeof( NODE ));
Successor->Parent = BestNode;
Successor->g = g;
Successor->h = (x-dx)*(x-dx) + (y-dy)*(y-dy); // should do sqrt(), but since we don't really
Successor->f = g+Successor->h; // care about the distance but just which branch looks
Successor->x = x; // better this should suffice. Anyayz it's faster.
Successor->y = y;
Successor->NodeNum = TileNumS;
//再插入Open表中,同时排序。
Insert(Successor); // Insert Successor on OPEN list wrt f
for( c =0; c <8; c++) if ( BestNo
457
de->Child[c] == NULL ) // Add Old to the list of BestNode's Children (or Successors).
break;
BestNode->Child[c] = Successor;
}
}

哈哈!A*算法我懂了!当然,我希望你有这样的感觉!不过我还要再说几句。仔细看看这个程 序,你会发现,这个程序和我前面说的伪程序有一些不同,在GenerateSucc函数中,当子节点 在Closed表中时,没有将子节点从Closed表中删除并放入Open表中。而是直接的重新的计算该 节点的所有子节点的估价值(用PropagateDown函数)。这样可以快一些!另当子节点在 Open 表和Closed表中时,重新的计算估价值后,没有重新的对Open表中的节点排序,我有些想不通, 为什么不排呢?:-(,会不会是一个小小的BUG。你知道告诉我好吗?


/* 我曾看过一些有关A*算法的程序,不过写得比较简洁、易懂的还是风云写的A*算法 教学实例(风云工作室), 但是这个算法并没有进行优化,该程序要用到实际应用中,还会有一定的限制, 所以我对该算法进行了改进,并加上更详细的算法说明,使其具有更好的教学作用 和实用价值。开始前我先给出A*算法的基本思路:
问题:求出2D的迷宫中起始点S到目标点E的最短路径?
算法: findpath()
{
把S点加入树根(各点所在的树的高度表示从S点到该点所走过的步数);
把S点加入排序队列(按该点到E点的距离排序+走过的步数从小到大排序);
1、排序队列sort_queue中距离最小的第一个点出列,并保存入store_queue中
2、从出列的点出发,分别向4个(或8个)方向中的一个各走出一步
3、并估算第2步所走到位置到目标点的距离,并把该位置加入树,
最后把该点按距离从小到大排序后并放入队列中。(由trytile函数实现)。
4、如果该点从四个方向上都不能移动,则把该点从store_queue中删除
5、回到第一点,直到找到E点则结束
从目标点回溯树,直到树根则可以找到最佳路径,并保存在path[]中
}
*/
/*========================================================================

本程序参考了风云的最短路径代码(http://member.nease.com/~cloudwu),
并加以改进和优化:
1、把原来用于存放已处理节点的堆栈改为(store_queue)队列,这样在从
sort_queue队列出列时可直接放入store_queue中。
2、解除了地图大小的限制(如果有64K内存限制时,地图大小只能是180x180)
3、删除了原程序中的一些冗余,见程序中的注释。
4、程序继续使用dis_map数组保存各点历史历史最佳距离,也包含了某点是否已经
经过的信息,虽然这样做可能会比使用链表多用一些内存,但是在搜索时可以
节省不时间。
5、程序更具有实用性,可直接或修改后运用于你的程序中,但请你使用该代码后
应该返回一些信息给我,如算法的改进或使用于什么程序等。
本程序可以用Borland C++或DJGPP编译,并附带有一个数据文件 map.dat,
保存有地图的数据,(注:该地图文件格式与风云的原代码的地图格式不一样)
-------------------------------------------------------------------------*/
//#define NDEBUG
#include <stdio.h>
#include <conio.h>
#include <assert.h>
#include <stdlib.h>

#define tile_num(x,y) ((y)*map_w+(x)) //将 x,y 坐标转换为地图上块的编号
#define tile_x(n) ((n)%map_w) //由块编号得出 x,y 坐标
#define tile_y(n) ((n)/map_w)

#define MAPMAXSIZE 180 //地图面积最大为 180x180,如果没有64K内存限制可以更大
#define MAXINT 32767

//树结构, 比较特殊, 是从叶节点向根节点反向链接,方便从叶节点找到根节点
typedef struct tree_node *TREE;

struct tree_node {
int h; //节点所在的高度,表示从起始点到该节点所有的步数
int tile; //该节点的位置
TREE father; //该节点的上一步
};

//链接结构,用于保存处理过的和没有处理过的结点
typedef struct link_node *LINK;

struct link_node {
TREE node;
int f;
LINK next;
};

LINK sort_queue; // 保存没有处理的行走方法的节点
LINK store_queue; // 保存已经处理过的节点 (搜索完后释放)

unsigned char * map; //地图数据
unsigned int * dis_map; //保存搜索路径时,中间目标地最优解

int map_w,map_h; //地图宽和高
int start_x,start_y,end_x,end_y; //地点,终点坐标

// 初始化队列
void init_queue()
{
sort_queue=(LINK)malloc(sizeof(*sort_queue));
sort_queue->node=NULL;
sort_queue->f=-1;
sort_queue->next=(LINK)malloc(sizeof(*sort_queue));
sort_queue->next->node=NULL;
sort_queue->next->f=MAXINT;
sort_queue->next->next=NULL;

store_queue=(LINK)malloc(sizeof(*store_queue));
store_queue->node=NULL;
store_queue->f=-1;
store_queue->next=NULL;
}

// 待处理节点入队列, 依靠对目的地估价距离插入排序
void enter_queue(TREE node,int f)
{
LINK p=sort_queue,father,q;
while(f>p->f) {
father=p;
p=p->next;
assert(p);
}
q=(LINK)malloc(sizeof(*q));
assert(sort_queue);
q->f=f,q->node=node,q->next=p;
father->next=q;
}

// 将离目的地估计最近的方案出队列
TREE get_from_queue()
{
LINK bestchoice=sort_queue->next;
LINK next=sort_queue->next->next;
sort_queue->next=next;

bestchoice->next=store_queue->next;
store_queue->next=bestchoice;
return bestchoice->node;
}

// 释放栈顶节点
void pop_stack()
{
LINK s=store_queue->next;
assert(s);
store_queue->next=store_queue->next->next;
free(s->node);
free(s);
}

// 释放申请过的所有节点
void freetree()
{
int i;
LINK p;
while(store_queue){
p=store_queue;
free(p->node);
store_queue=store_queue->next;
free(p);
}
while (sort_queue) {
p=sort_queue;
free(p->node);
sort_queue=sort_queue->next;
free(p);
}
}

// 估价函数,估价 x,y 到目的地的距离,估计值必须保证比实际值小
int judge(int x,int y)
{
int distance;
distance=abs(end_x-x)+abs(end_y-y);
return distance;
}

// 尝试下一步移动到 x,y 可行否
int trytile(int x,int y,TREE father)
{
TREE p=father;
int h;
if (map[tile_num(x,y)]!=' ') return 1; // 如果 (x,y) 处是障碍,失败
//这一步用来判断(x,y)点是否已经加入队列,多余可以删除,因为dis_map已经
//保存该点是否已经保存
//while (p) {
// if (x==tile_x(p->tile) && y==tile_y(p->tile)) return 1; //如果 (x,y) 曾经经过,失败
// p=p->father;
//}
h=father->h+1;
if (h>=dis_map[tile_num(x,y)]) return 1; // 如果曾经有更好的方案移动到 (x,y) 失败
dis_map[tile_num(x,y)]=h; // 记录这次到 (x,y) 的距离为历史最佳距离

// 将这步方案记入待处理队列
p=(TREE)malloc(sizeof(*p));
p->father=father;
p->h=father->h+1;
p->tile=tile_num(x,y);
enter_queue(p,p->h+judge(x,y));
return 0;
}

// 路径寻找主函数
int * findpath(void)
{
TREE root;
int i,j;
int * path;
memset(dis_map,0xff,map_h*map_w*sizeof(*dis_map)); //填充dis_map为0XFF,表示各点未曾经过
init_queue();
root=(TREE)malloc(sizeof(*root));
root->tile=tile_num(start_x,start_y);
root->h=0;
root->father=NULL;
enter_queue(root,judge(start_x,start_y));
for (;;) {
int x,y,child;
TREE p;
root=get_from_queue();
if (root==NULL) {
return NULL;
}
x=tile_x(root->tile);
y=tile_y(root->tile);
if (x==end_x && y==end_y) break; // 达到目的地成功返回

child=trytile(x,y-1,root); //尝试向上移动
child&=trytile(x,y+1,root); //尝试向下移动
child&=trytile(x-1,y,root); //尝试向左移动
child&=trytile(x+1,y,root); //尝试向右移动
//child&=trytile(x+1,y-1,root);//尝试向右上移动
//child&=trytile(x+1,y+1,root); //尝试向右下移动
//child&=trytile(x-1,y+1,root); //尝试向左下移动
//child&=trytile(x-1,y-1,root); //尝试向左上移动

if (child!=0)
pop_stack(); // 如果四个方向均不能移动,释放这个死节点
}

// 回溯树,将求出的最佳路径保存在 path[] 中
path=(int*)malloc((root->h+2)*sizeof(int));
assert(path);
for (i=0;root;i++) {
path[i]=root->tile;
root=root->father;
}
path[i]=-1;
freetree();
return path;
}

void printpath(int *path)
{
int i;
if(path==NULL) return ;
for (i=0;path[i]>=0;i++) {
gotoxy(tile_x(path[i])+1,tile_y(path[i])+1);
cprintf(".");
}
}

int readmap()
{
FILE *f;
int i,j;
f=fopen("map.dat","r");
assert(f);
fscanf(f,"%d,%d\n",&map_w,&map_h);
map=malloc(map_w*map_h+1);
assert(map);
for(i=0;i<map_h;i++)
fgets(map+tile_num(0,i),map_w+2,f);
fclose(f);
start_x=-1,end_x=-1;
for (i=0;i<map_h;i++)
for (j=0;j<map_w;j++) {
if (map[tile_num(j,i)]=='s') map[tile_num(j,i)]=' ',start_x=j,start_y=i;
if (map[tile_num(j,i)]=='e') map[tile_num(j,i)]=' ',end_x=j,end_y=i;
}
assert(start_x>=0 && end_x>=0);
dis_map=malloc(map_w*map_h*sizeof(*dis_map));
assert(dis_map);
return 0;
}

void showmap()
{
int i,j;
clrscr();
for (i=0;i<map_h;i++) {
gotoxy(1,i+1);
for (j=0;j<map_w;j++)
if (map[tile_num(j,i)]!=' ') cprintf("O");
else cprintf(" ");
}
gotoxy(start_x+1,start_y+1);
cprintf("s");
gotoxy(end_x+1,end_y+1);
cprintf("e");
}

int main()
{
int * path;
readmap();
showmap();
getch();
path=findpath();
printpath(path);
if(dis_map) free(dis_map);
if(path) free(path);
if(map) free(map);
getch();
return 0;
}
/*===============================================================================
地图文件:map.dat
79,24
ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo
o o o
o ooooooo o o
o o o oooooooooooooo o
o s o o o
oooooooooooooooooo o o
o oooooooooooooooooooooooooo oooooooo o
o oooooo o oooo o o o
o o o ooo ooo o
o oooo oooo o
o o oooooooooooooooooooooooooooooooooooooooooooooo
o oooooooooooooooooooooooo o
o o
o o
ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo o
o o ooooooooooo
o o ooooooo o o
o o o o o
o ooooooooooo oooooooooo o o
o o e ooo o o
o ooooo o o o
o o oooooooooooooooooo oooooooo o
o o o
ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo
---------------------------------------------------------------------------------*/
newtoon2002 2001-08-22
  • 打赏
  • 举报
回复
to starfish: 斑竹大哥,能不能给我讲讲A*,B*算法?谢谢!
jucee 2001-08-22
  • 打赏
  • 举报
回复
push
孩皮妞野 2001-08-22
  • 打赏
  • 举报
回复
好东西。
anjun 2001-08-21
  • 打赏
  • 举报
回复
这么繁啊
starfish 2001-08-15
  • 打赏
  • 举报
回复
如果使用链表存储指针域的话,那就没有空指针域存在了,但是那样的话代价就是遍历链表的效率太低,所以比较好的办法还是用数组存储指针域,因为可以根据下表直接结算出数组元素的位置,注意,这里的位置都是指硬盘上的位置,所以只有用数组保存指针才能最大限度地减小访问硬盘的次数。而要用数组保存指针,其中的空指针域就无法避免。
one_add_one 2001-08-15
  • 打赏
  • 举报
回复
除非你重新发明一个数据结构,然后取名叫“传统B+树”

不过要注意版权!
(这是个严肃的问题:)
anjun 2001-08-15
  • 打赏
  • 举报
回复
真的是一点办法都没有吗?
starfish 2001-08-14
  • 打赏
  • 举报
回复
确实是没有好办法,这点代价还是需要付出的。
goldcattle 2001-08-14
  • 打赏
  • 举报
回复
如果你用传统的b+加树那是无法避免的,除非你用其他算法
one_add_one 2001-08-14
  • 打赏
  • 举报
回复
最好的方法:


不要用B+树!
anjun 2001-08-14
  • 打赏
  • 举报
回复
快啊
starfish 2001-08-13
  • 打赏
  • 举报
回复
我查查书先,已经快要忘记B+树了:)

33,010

社区成员

发帖
与我相关
我的任务
社区描述
数据结构与算法相关内容讨论专区
社区管理员
  • 数据结构与算法社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧