/**
* @file Stack.h
* Test environmentof IDE: VC++ 6.0
* 顺序栈基本操作的实现
*/
#ifndef _STACK_H
#define _STACK_H
#define STACK_INIT_SIZE 100 //初始分配量
#define STACK_INCREAMENT 10 //分配增量
typedef struct SqStack
{
SElemType* base;
SElemType* top;
int stacksize;
}SqStack;
//栈空
int StackEmpty(const SqStack& S)
{
if(S.top == S.base)
return true;
else
return false;
}
void InitStack(SqStack& S)
{
S.base = (SElemType*)malloc(STACK_INIT_SIZE * sizeof(SElemType));
if(NULL == S.base)
exit(0);
S.top = S.base;
S.stacksize = STACK_INIT_SIZE;
}
void Push(SqStack& S, SElemType& e)
{
//栈满,增加空间
if(S.top - S.base >= S.stacksize)
{
S.base = (SElemType*)realloc(S.base,
(S.stacksize + STACK_INCREAMENT) * sizeof(SElemType));
if(NULL == S.base)
exit(0);//分配失败
S.top = S.base + S.stacksize;
S.stacksize += STACK_INCREAMENT;
}
*(S.top) = e;
S.top++;
}
int Pop(SqStack& S, SElemType& e)
{
if(!StackEmpty(S))
{
S.top--;
e = *(S.top);
return true;
}
else //栈空
return false;
}
void DestroyStack(SqStack& S)
{
free(S.base);
S.base = NULL;
S.top = NULL;
S.stacksize = 0;
}
#endif
/**
* @file Maze.cpp
* Test environment of IDE: VC++ 6.0
* 迷宫的非递归实现
* 参考: 教材 P51
* 由于该方法采取的是穷举法,并且有8个方向可以尝试
* 显然, 路径长度最多接近(n^2)/2. 最短为对角线长度,即 n*根号2
* 因此时间复杂度上界为O(n^16),下届为O(n^8).
* 空间复杂度为矩阵大小,即O(n^2)
*/
#include <iostream>
//坐标位置
typedef struct PosType
{
int x;
int y;
}PosType;
//栈元素类型
typedef struct SElemType
{
int ord; //通道块在路径上的"序号"
PosType seat; //通道块在迷宫中的"坐标"
int di; //通道块走向下一个通道块的"方向".
//"0,1,2,3,4,5,6,7"分别表示 "右,右下,下,左下,左,左上,上,右上" 八个方向
}SElemType;
#define MAXLENGTH 30//迷宫的最大行列
typedef int MazeType[MAXLENGTH][MAXLENGTH]; //迷宫矩阵
/** 本文件内的全局变量 */
static MazeType m; //迷宫矩阵
static int curstep = 1; //当前足迹,入口初值为1.
#include "stack.h" //引入栈的基本操作
/** 设置n x n迷宫矩阵 */
void SetMaze(int n);
/** 输出n x n迷宫矩阵 */
void Display(const int n);
/** 输出迷宫路径 */
void Print(SqStack& S);
/** 判断是否可通过. 可通过为1, 不可通过为0. */
bool Pass(const PosType& pos);
/** 留下足迹. 将当前通过的路径标记为curstep. */
void FootPrint(const PosType& pos);
/** 根据pos位置的di方向,求下一个位置 */
void NextPos(PosType& pos,int di);
/** 标记为不能通过的路径.(标记为0). */
void MarkPrint(const PosType& seat);
/**
* 若迷宫中存在从入口start到出口end的通道,则求得一条存放在
* 栈中(从栈底到栈顶),并返回true,否则返回false.
*/
bool MazePath(SqStack& S, const PosType& start, const PosType& end);
int main(int argc, char* argv[])
{
int n=0;
SqStack S;
PosType start,end;
std::cout << "请设置n x n迷宫的n值大小:";
std::cin >> n;
std::cout << "请设置迷宫的入口与出口位置(格式:x y).\n";
std::cout << "入口:";
std::cin >> start.x >> start.y;
std::cout << "出口:";
std::cin >> end.x >> end.y;
SetMaze(n);
Display(n);
if(MazePath(S,start,end))
{
std::cout << "找到一条通路.\n\n";
Display(n);
Print(S);
}
else
std::cout << "不存在通路.\n\n";
DestroyStack(S);//释放占空间,以防内存泄露.
return 0;
}
void SetMaze(const int n)
{
std::cout
<< "请从左至右,从上至下依次设置迷宫" << std::endl
<< "(用0表示不通,用1表示通.)" << std::endl;
for(int j=0; j<n; j++)
for(int i=0; i<n; i++)
std::cin >> m[j][i];
}
void Display(const int n)
{
std::cout << "\t迷宫结构\n";
for(int j=0; j<n; j++)
for(int i=0; i<n; i++)
{
std::cout << m[j][i] << " ";
if(i == n-1)
std::cout << std::endl;
}
std::cout << std::endl;
}
void Print(SqStack& S)
{
SElemType e;
while(!StackEmpty(S))
{
Pop(S, e);
std::cout << e.seat.x << "," << e.seat.y << std::endl;
}
}
bool MazePath(SqStack& S, const PosType& start, const PosType& end)
{
PosType curpos;
SElemType e;
InitStack(S);
curpos = start;
do{
if(Pass(curpos))
{//当前位置可以通过
FootPrint(curpos); //留下足迹
e.ord = curstep;
e.seat = curpos;
e.di = 0; //右方向
Push(S,e);//加入路径,保存信息.
curstep++;
if(curpos.x == end.x && curpos.y == end.y)
return true; //到达终点
NextPos(curpos, e.di); //选择下一个位置,是当前位置的右邻.
}
else
{//当前位置不可通过
if(!StackEmpty(S))
{
Pop(S, e);//回溯
curstep--;
while(e.di == 7 && !StackEmpty(S))
{//将不能通过的做标记
MarkPrint(e.seat);
Pop(S,e);//回溯
curstep--;
}
if(e.di < 7)
{//更换下一个方向进行
e.di++;
Push(S,e);//加入路径
curstep++;
curpos = e.seat;
NextPos(curpos, e.di);//设置当前路径为下一个di方向的通道块.
}
}
}
}while(!StackEmpty(S));
return false;
}
bool Pass(const PosType& pos)
{
if(m[pos.x][pos.y] == 1)
return true;
else
return false;
}
void FootPrint(const PosType& pos)
{
m[pos.x][pos.y] = curstep;
}
void NextPos(PosType& pos,int di)
{//分别为"右,右下,下,左下,左,左上,上,右上"方向的增量
PosType direc[8] = {{0,1},{1,1},{1,0},{1,-1},
{0,-1},{-1,-1},{-1,0},{-1,1}};
pos.x += direc[di].x;
pos.y += direc[di].y;
}
void MarkPrint(const PosType& seat)
{
m[seat.x][seat.y] = 0;
}