利用顺序栈实现迷宫穷举走法 (光标移动函数,延时函数)

顺序栈:一种存储结构为顺序具有先进后出性质的线性表。
穷举法走迷宫:就是探索式走法,设定一个探索顺序和初始方向比如开始探索上,逆时针轮,上、左、下、右。
在这里插入图片描述
我的迷宫是用一个1010的字符数组存储的。
栈对与实现穷举法实现迷宫具有独特的优势。
这种优势总结为一点就是吞吐轨迹点。
怎么讲呢,从上往下第一个‘
’(星号)为起点,第二个为终点。
我这里是设开始方向为右侧,按顺时针方向转。即右、下、左、上。
从起点开始探索,当探索到的空间为“ ”(空格)时该坐标点入栈,该点标记为“@”。
当探索到的空间不为“ ”(空格时)换一个方向,当所有方向都探索完毕,而仍无路可走时,该坐标点出栈并标记为“!”(感叹号)。直到找到第二个‘*’(星号),探索完毕。
我们知道,栈的特点是先进后出,所以如果直接将栈遍历输出,得到的坐标路径是反的。若想要正的就得再找建立一个栈,或者数组,将路径坐标正序输出。
在栈的结构体的设计我是这么写的

typedef struct stack {
	elemtype* top;
	elemtype* base;
	int startsize;//初始空间 当栈的空间不足时可用以做开辟空间的标准 当你在走一个大迷宫                           //的时候就排的上用场了
}stack, *pstack;

top,base,是两个元素指针,存元素的地址。
元素数据含有轨迹点坐标的信息(x,y);
一个十位数,十位上是x,个位上是y;
读取的时候用算法处理好就行了。
下面是map.h 代码

#pragma once
#include<malloc.h>
#include<Windows.h>
#define Beginsize 100
#define Incrementsize 10

#define elemtype int
char map[10][10] = { '#','#','#','#','#','#','#','#','#','#',
				   '#',' ',' ','#',' ',' ',' ','#',' ','#',
				   '#',' ',' ','#',' ',' ',' ','#',' ','#',
					'#',' ',' ',' ',' ','#','#',' ',' ','#',
					'#',' ','#','#','#',' ',' ',' ',' ','#',
					'#',' ',' ',' ','#',' ',' ',' ',' ','#',
					'#',' ','#',' ',' ',' ','#',' ',' ','#',
					'#',' ','#','#','#',' ','#','#',' ','#',
					'#','#',' ','*',' ',' ',' ',' ',' ','#',
					'#','#','#','#','#','#','#','#','#','#', };

 

typedef struct stack {
	elemtype* top;
	elemtype* base;
	int startsize;
}stack, *pstack;

int InitStack(pstack p)
{
	p->base = (elemtype*)malloc(Beginsize * sizeof(elemtype));
	if (!p->base) return 0;
	p->top = p->base;
	p->startsize = Beginsize;
}

void ClearStack(pstack p)  //清空栈 
{
	p->top = p->base;
}

void DestroyStack(pstack p)
{
	free(p);
}

int Push(pstack p, elemtype e) //入栈 
{
	if (p->top - p->base >= p->startsize)
	{
		p->base = (elemtype*)realloc(p->base, (p->startsize + Incrementsize) * sizeof(elemtype));
		if (!p->base) return 0;
		p->top = p->base + p->startsize;
		p->startsize += Incrementsize;
	}
	*p->top++ = e;
}

int Pop(pstack p, elemtype* e)//出栈 
{
	if (p->base == p->top) return 0;
	*e = *--p->top;
}

void StackPutAll(pstack p)  //全栈滚蛋 
{
	elemtype e;
	while (p->base != p->top)
	{
		Pop(p, &e);
		printf("%d", e);
	}
	printf("\n");
}

int StackEmpty(pstack p)  // 判断栈是否为空 
{
	if (p->base == p->top)  return 0;
	else
		return 1;
}

void Gettop(pstack p, elemtype* e) // 栈顶元素的获取 
{
	if (StackEmpty(p))
		*e = *(p->top - 1);
}

void gotoxy(int x, int y)//光标移动
{
	COORD pos;
	pos.X = x;   //横坐标
	pos.Y = y;   //纵坐标
	SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos);
}

void PutMap() //打印地图及轨迹
{
	int i, j;
	for (i = 0; i < 10; i++)
	{
		for (j = 0; j < 10; j++)
			printf("%c", map[i][j]);
		printf("\n");
	}
}

void WayExplore(pstack p) //穷举走法
{
	int i = 1;
	int j = 1;
	elemtype a;
	//int wei;
	bool row=0;
	
	while (1)
	{
		 while (1)
	{
		//右走  1 右
		if (map[i][j+1] == ' ')
		{
			a = i * 10 + (++j)*1;
			Push(p, a);
			map[i][j] = '@';
			break;
		}
		//下走  2下走
		if (map[i+1][j] == ' ')
		{
			a = (++i) * 10 + j*1;
			Push(p, a);
			map[i][j] = '@';
			break;
		}
		
		//左走
		if (map[i][j - 1] == ' ')
		{
			a = i * 10 + (--j)*1;
			Push(p, a);
			map[i][j] = '@';
			break;
		}
		//上走
		if (map[i-1][j] == ' ')
		{
			a = (--i) * 10 + j*1;
			Push(p, a);
			map[i][j] = '@';
			break;
		}
		row = 1;
		break;
	}//走步
	 if (row == 1)  //后退
	 {
		 Pop(p,&a);
		 i = a / 10;
		 a %= 10;
		 j = a ;
		// wei = a % 10;
		 if (map[i][j + 1] == ' ' || map[i + 1][j] == ' ' || map[i][j - 1] == ' ' || map[i - 1][j] == ' ')
		 {
			 a = i * 10 + j * 1 ;
			 Push(p, a);
		 }
		 else
			 if(map[i][j]!='#')
			 map[i][j] = '!';
		 row = 0;
	 }
	 PutMap();
	 if (map[i][j + 1] =='*'|| map[i + 1][j]=='*'|| map[i][j - 1] == '*'|| map[i - 1][j] == '*')
		 break;  //结束
	 Sleep(10); //延时函数 让其探索过程放慢 一种观察手段
	 gotoxy(0, 0); //把光标放在起始位
	}
	
}

我执行完这个程序看到的是
在这里插入图片描述
这各图我觉得不好看,于是我重新折腾了一下,让这个栈输出到另一个栈里去
再创一个图,在输出新栈的同时,在新图上标出轨迹,感叹号没了,还可以看到它走一波麻溜的正确路径。得到下图
在这里插入图片描述
代码如下同样放在map.h中

void WayTrack(pstack p,pstack q) //轨迹重输
{
	int i, j,k=0;
	int e[50];
	system("cls");
	char NewMap[10][10] = { '#','#','#','#','#','#','#','#','#','#',
				   '#','*',' ','#',' ',' ',' ','#',' ','#',
				   '#',' ',' ','#',' ',' ',' ','#',' ','#',
					'#',' ',' ',' ',' ','#','#',' ',' ','#',
					'#',' ','#','#','#',' ',' ',' ',' ','#',
					'#',' ',' ',' ','#',' ',' ',' ',' ','#',
					'#',' ','#',' ',' ',' ','#',' ',' ','#',
					'#',' ','#','#','#',' ','#','#',' ','#',
					'#','#',' ','*',' ',' ',' ',' ',' ','#',
					'#','#','#','#','#','#','#','#','#','#', };
	elemtype a;
	
	while (p->top!=p->base)
	{
		Pop(p, &a);
		Push(q, a);
	}  //顺序倒置
	while (q->top != q->base)
	{
		gotoxy(0, 0);
		Sleep(100);
		Pop(q, &a);
		e[k++] = a;
		i = a / 10;
		a %= 10;
		j = a ;
		NewMap[i][j] = '@';
		for (int num = 0; num < 10; num++)
		{
			for (int numc = 0; numc < 10; numc++)
				printf("%c", NewMap[num][numc]);
			printf("\n");
		}
	}
	for (int num=0; num < k; num++)
	{
		i = e[num]/ 10;
		e[num] %= 10;
		j = e[num] ;
		printf("(%d,%d)->", i, j);
	}

	printf("\n");
}

主函数代码如下

#include<stdio.h>
#include "map.h"
int main()
{
	elemtype e;
	stack Sa;
	stack Sa2;
	InitStack(&Sa);
	InitStack(&Sa2);
	WayExplore(&Sa);
	WayTrack(&Sa, &Sa2);
	system("pause");
	return 0;
}

我这里用了另外两个函数,一个是Sleep()函数,在windows.h头文件中作用是放慢探索过程让我们可以更好地观察算法的正确与否。Sleep(1000)=1s;(Sleep的S是大写)
另一个是光标移动函数

void gotoxy(int x, int y)//光标移动
{
	COORD pos;
	pos.X = x;   //横坐标
	pos.Y = y;   //纵坐标
	SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos);
}

光标移动函数顾名思义就是改变光标的位置
由于我要实现的让程序的探索过程可视化,所以每走一步就需要打印出一个图。
开始我用的刷屏函数,但是刷屏函数用起来很不好看,它会让屏幕一闪一闪。
而改变光标位置就不会有这个问题了。
光标移动函数原理
链接里的函数和上面这个是一样的,只不过上面的更清爽些。
欢迎留言讨论!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值