一直对栈的用作回溯处理这些用法不熟悉,所以迷宫用栈的深度搜索一直都没写出来,今天又看看了严老师的数据结构,参考了上面的算法,把迷宫递归和用栈回溯都写了下,用的是类C语言,代码显得有些冗杂
先是用递归写出来的,关键部分注释了下:
/**
********************************************************************
purpose: 迷宫递归算法
maze[][]是迷宫的二维图,path[]是记录路径的数组
point 是自定义结构体,有x、y表示坐标
*********************************************************************/
void maze_path( int maze[][ 5 ], int path[],point start,point des, int length)
... {
int i;
bool flag=false;
if(start.x==des.x&&start.y==des.y) //如果是目的点
...{
for (i=1;i<length;i++)
printf("%d->",path[i]);
printf("%d 查找完毕 ",(start.x-1)*3+start.y);
}
else
...{
maze[start.x][start.y]=1;
path[length]=(start.x-1)*3+start.y; /**//*maze是个5*5的数组,由于外面要包一层墙,所以核心数组是个3*3的迷宫图,分别以1~9标号,映射方程为location=(x-1)*3+y */
for(i=0;i<4;i++)
...{
int next_x=start.x+dir[i][0];
int next_y=start.y+dir[i][1];
if(!maze[next_x][next_y])
...{
flag=true;
point temp;
temp.x=next_x;
temp.y=next_y;
maze_path(maze,path,temp,des,++length);
}
}
if(flag)
return; /***这一句自认为最重要,表示当前路径搜索不出通路,则中断该搜索分支,可以用笔在纸上单步模拟下,原理就清楚了*/
}
}
purpose: 迷宫递归算法
maze[][]是迷宫的二维图,path[]是记录路径的数组
point 是自定义结构体,有x、y表示坐标
*********************************************************************/
void maze_path( int maze[][ 5 ], int path[],point start,point des, int length)
... {
int i;
bool flag=false;
if(start.x==des.x&&start.y==des.y) //如果是目的点
...{
for (i=1;i<length;i++)
printf("%d->",path[i]);
printf("%d 查找完毕 ",(start.x-1)*3+start.y);
}
else
...{
maze[start.x][start.y]=1;
path[length]=(start.x-1)*3+start.y; /**//*maze是个5*5的数组,由于外面要包一层墙,所以核心数组是个3*3的迷宫图,分别以1~9标号,映射方程为location=(x-1)*3+y */
for(i=0;i<4;i++)
...{
int next_x=start.x+dir[i][0];
int next_y=start.y+dir[i][1];
if(!maze[next_x][next_y])
...{
flag=true;
point temp;
temp.x=next_x;
temp.y=next_y;
maze_path(maze,path,temp,des,++length);
}
}
if(flag)
return; /***这一句自认为最重要,表示当前路径搜索不出通路,则中断该搜索分支,可以用笔在纸上单步模拟下,原理就清楚了*/
}
}
失败之处在于没有用C++,感觉有些代码为了追求易读性,反而看上去冗杂了许多。比如point,最初为了程序更加直观,最后反而写出来更加不通读了。所以在写利用栈的迷宫算法代码时,没有用point,感觉也比较麻烦,先把算法的汉语贴出来,再来看看代码就很容易理解了:
设定当前位置的初值为入口位置;
do ... {
若当前位置可通,
则...{
将当前位置插入栈顶; // 纳入路径
若该位置是出口位置,则算法结束;
// 此时栈中存放的是一条从入口位置到出口位置的路径
否则切换当前位置的东邻方块为新的当前位置;
}
否则
...{
若栈不空且栈顶位置尚有其他方向未被探索,
则设定新的当前位置为: 沿顺时针方向旋转找到的栈顶位置的下一相邻块;
若栈不空但栈顶位置的四周均不可通,
则...{ 删去栈顶位置; // 从路径中删去该通道块
若栈不空,则重新测试新的栈顶位置,
直至找到一个可通的相邻块或出栈至栈空;
}
}
} while (栈不空);
do ... {
若当前位置可通,
则...{
将当前位置插入栈顶; // 纳入路径
若该位置是出口位置,则算法结束;
// 此时栈中存放的是一条从入口位置到出口位置的路径
否则切换当前位置的东邻方块为新的当前位置;
}
否则
...{
若栈不空且栈顶位置尚有其他方向未被探索,
则设定新的当前位置为: 沿顺时针方向旋转找到的栈顶位置的下一相邻块;
若栈不空但栈顶位置的四周均不可通,
则...{ 删去栈顶位置; // 从路径中删去该通道块
若栈不空,则重新测试新的栈顶位置,
直至找到一个可通的相邻块或出栈至栈空;
}
}
} while (栈不空);
我的代码基本上参考上面伪代码,中有几个需说明下:
1. 加入了一个布尔值FindFlag,主要为了辨别是否已找到出口
2. 仍然参考了上面的坐标映射,计算公式仍是 location=(x-1)*3+y
int
dir[
4
][
2
]
=
...
{...{1,0},...{0,1},...{-1,0},...{0,-1}}
;
//
方向的控制,很多参考书都是采用这方法,感觉不错
int MazeFind( int maze[][ 5 ], int startX, int startY, int desX, int desY)
... {
bool FindFlag=false;
stack MazeStack;
initStack(MazeStack);
do
...{
if(!maze[startX][startY])
...{
push(MazeStack,(startX-1)*3+startY);
if (startX==desX&&startY==desY)
FindFlag=true;
else
...{
int direction=maze[startX][startY]++;
startX=startX+dir[direction][0];
startY=startY+dir[direction][1];
}
}
else
...{
startX=MazeStack.array[MazeStack.top]/3+1;
startY=MazeStack.array[MazeStack.top]%3;
if(!empty(MazeStack)&&maze[startX][startY]<4)
...{
int direction=maze[startX][startY]++;
startX=startX+dir[direction][0];
startY=startY+dir[direction][1];
}
if(!empty(MazeStack)&&maze[startX][startY]>=4)
...{
int location=pop(MazeStack);
startX=location/3+1;
startY=location%3;
}
}
} while(!empty(MazeStack)&&!FindFlag);
if (empty(MazeStack))
return 0;
else
...{
for(int i=0;i<MazeStack.top;i++)
printf("%d->",MazeStack.array[i]);
printf("%d",MazeStack.array[i]);
printf(" ");
return 1;
}
}
int MazeFind( int maze[][ 5 ], int startX, int startY, int desX, int desY)
... {
bool FindFlag=false;
stack MazeStack;
initStack(MazeStack);
do
...{
if(!maze[startX][startY])
...{
push(MazeStack,(startX-1)*3+startY);
if (startX==desX&&startY==desY)
FindFlag=true;
else
...{
int direction=maze[startX][startY]++;
startX=startX+dir[direction][0];
startY=startY+dir[direction][1];
}
}
else
...{
startX=MazeStack.array[MazeStack.top]/3+1;
startY=MazeStack.array[MazeStack.top]%3;
if(!empty(MazeStack)&&maze[startX][startY]<4)
...{
int direction=maze[startX][startY]++;
startX=startX+dir[direction][0];
startY=startY+dir[direction][1];
}
if(!empty(MazeStack)&&maze[startX][startY]>=4)
...{
int location=pop(MazeStack);
startX=location/3+1;
startY=location%3;
}
}
} while(!empty(MazeStack)&&!FindFlag);
if (empty(MazeStack))
return 0;
else
...{
for(int i=0;i<MazeStack.top;i++)
printf("%d->",MazeStack.array[i]);
printf("%d",MazeStack.array[i]);
printf(" ");
return 1;
}
}