迷宫(non-recursion)(即栈实现)

/**
* @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;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值