-
需求分析:包含题目要求,程序功能,运行方式,测试数据等
将马随机放在国际象棋的8×8棋盘Board[8][8]的某个方格中,马按走棋规则进行移动。要求每个方格只能进入一次,走遍棋盘上全部64个方格。编写非递归程序,求出马的行走路线,并按求出的行走路线,将数字1,2,3,…,64依次填入8×8的方阵,输出之。要求给出其中的100个解。
为了完成目的,需要定义一个二维数组Board[8][8],同时定义在x,y方向棋子可以行走的方向xd [],yd [],为了简便,定义define M 8,方便调试程序。
同时定义基础结构和栈相关函数。
定义顺序栈结构: 定义存储马位置和方向的结构体:
typedef struct{ typedef struct{
pos *base; int x,y;//位置
pos *top;
int stacksize; int d;//方向
} SqStack;//顺序栈定义 }pos;//存储马参数结构体
StackEmpty(SqStack S)判断栈是否空;Push(SqStack &S, pos e) 插入元素e为新的栈顶元素;Pop(SqStack &S, pos &e)删除S的栈顶元素,用e返回其值。
通过输入棋子不同的初始值,把走过位置数据放入栈中,当出现错误时退栈返回,再向另一个方向行走,循环这个步骤,直到走完整个棋盘时,输出存入二维数组Board的值。
-
概要设计:包含抽象数据类型定义,程序模块等
定义棋盘和方向:
int Board[M][M] = {0};//棋盘,设置为二维数组,做全局变量
int xd [] = { -2, -1, 1, 2, 2, 1, -1, -2 };//可以在x方向上行走的方向
int yd [] = { 1, 2, 2, 1, -1, -2, -2, -1 };//可以在y方向上行走的方向
定义栈初始化函数InitStack(SqStack &S)构造一个空栈S。StackEmpty(SqStack S)判断栈是否空;Push(SqStack &S, pos e) 插入元素e为新的栈顶元素;Pop(SqStack &S, pos &e)删除S的栈顶元素,用e返回其值。
定义pos结构体存储棋子位置,方向,在算法调用中实现马踏棋盘。程序定义栈模块,马踏棋盘模块,棋盘与方向模块,栈模块用于存储试错,马踏棋盘模块用于调用栈模块进行在棋盘上赋值并正确输入棋子的位置和方向。
#include <iostream>
#include<cstdlib>
#include <stack>
#include <iomanip>
using namespace std;
#define MAXSIZE 2147483647//栈长度设置为int型最大值
#define M 8
typedef struct{
int x,y;//位置
int d;//方向
}pos;//存储棋子参数结构体
typedef struct{
pos *base;
pos *top;
int stacksize;
} SqStack;//顺序栈定义
int Board[M][M] = {0};//棋盘,设置为二维数组,做全局变量
int xd [] = { -2, -1, 1, 2, 2, 1, -1, -2 };//可以在x方向上行走的方向
int yd [] = { 1, 2, 2, 1, -1, -2, -2, -1 };//可以在y方向上行走的方向
void InitStack(SqStack &S) {//构造一个空栈S
S.base = new pos[MAXSIZE];//为顺序栈动态分配一个最大容量为MAXSIZE的数组空间
if (!S.base)
exit(0); //存储分配失败
S.top = S.base; //top初始为base,空栈
S.stacksize = MAXSIZE; //stacksize置为栈的最大容量MAXSIZE
}
bool StackEmpty(SqStack S){//判断栈是否空
if(S.top == S.base){
return true;
}else{
return false;
}
}
bool StackOverflow(SqStack S){//判断栈是否满
if (S.top - S.base == S.stacksize){
return true;
}else{
return false;
}
}
void Push(SqStack &S, pos e) {//插入元素e为新的栈顶元素
if (S.top - S.base == S.stacksize)
cout<<"栈满。"; //栈满
*(S.top++) = e; //元素e压入栈顶,栈顶指针加1
}
pos Pop(SqStack &S, pos &e){//删除S的栈顶元素,用e返回其值
if(S.top == S.base)
cout<<"栈空";
e = *--S.top;
return e;
}
pos getTop(SqStack &S){//取栈顶元素值
if (S.top != S.base)//栈非空
return *(S.top - 1);//返回栈顶元素的值,栈顶指针不变
}
void output(){//输出马行走的结果
for(int x = 0;x<M;x++){
for(int y = 0;y<M;y++){
cout<<Board[x][y]<<" ";
}
cout<<endl;
}
cout<<"--------以上为输出结果-----------"<<endl;
}
void horsePlay(int x,int y){
int step = 1;//定义步数,目的是将步数赋给棋盘上二维数组
SqStack stack;
pos pos;
InitStack(stack);//初始化栈
pos.x = x;pos.y = y;//第一个棋子的位置
pos.d = 0;//第一个方向
Push(stack,pos);//将棋子位置入栈
Board[x][y] = step++;//第一个位置赋值为1,赋值后step为2
while (!StackEmpty(stack)) {//栈非空时继续循环
int static num = 1;//定义循环次数
if(step > M*M && num<=100){//当步数大于棋盘数输出结果
cout<<"这是第"<<num++<<"个结果"<<endl;
output();
}
Pop(stack,pos);//出栈,将栈中数据赋给位置结构体
int forword = 0;//定义用于方向的int常量forward
for(forword = pos.d;forword<8;forword++){//试探
if((Board[pos.x+xd[forword]][pos.y+yd[forword]]) == 0 &&
(pos.x+xd[forword]<M && pos.y+yd[forword]<M) &&
(pos.x+xd[forword]>=0 && pos.y+yd[forword]>=0)){
break;//当试探成功时结束循环对棋盘赋值
}
}
if(forword >= 8){//当方向大于8时候,试探错误,回退步数
Board[pos.x][pos.y] = 0;
step--;
}
else {//对棋盘赋值
pos.d = forword+1;//向下一个方向
Push(stack,pos);//下一个方向结果入栈
pos.x = pos.x + xd[forword];//马跳到下一个正确的坐标
pos.y = pos.y + yd[forword];
pos.d = 0;//方向置零
Board[pos.x][pos.y] = step++;//步数赋值给棋盘
Push(stack,pos);//当前入栈,为下一步试探准备
}
}
}
int main()
{
int x,y;
cout << "输入马在棋盘中的位置x:"<<endl;cin>>x;
cout << "输入马在棋盘中的位置y:"<<endl;cin>>y;
horsePlay(x,y);
return 0;
}
-
详细设计:抽象数据类型以及程序模块的具体实现,算法设计思想
构造一个空栈S, 初始化栈为顺序栈动态分配一个数组空间,插入元素e为新的栈顶元素,判断栈是否空,栈非空时继续循环,定义步数,目的是将步数赋给棋盘上二维数组。
主函数中输入棋子位置,将棋子位置入栈,第一个位置在棋盘Board上赋值为1,赋值后step为2,定义循环次数static num,当步数大于棋盘数(64)时输出结果,出栈,将栈中数据赋给位置结构体,定义用于方向的int常量forward,试探,当棋子位置合法时(棋子在x和y坐标均在棋盘上)当试探成功时且方向在8个棋子可走的方向之内时结束循环对棋盘赋值(当方向大于8时,试探错误,回退步数,走过的地方赋值为0,步数减一)。
对棋盘赋值,forword+1向下一个方向行走,并把下一个方向结果入栈,马跳到下一个正确的坐标,步数赋值给棋盘,方向置零,下一个坐标入栈,为下一步试探准备,当方向都错误时出栈并将前面结果赋值为0,步数减少,换方向继续行走,循环前面这些步骤,当步数大于棋盘数输出结果时,输出棋子行走的结果。
-
调试分析:包括算法的时间复杂度和空间复杂度分析等
算法horsePlay中,定义了栈非空时的while循环,里面还定义了试探方向的for循环,算法时间复杂度为n2;申请了栈的空间,空间复杂度为n。
输出函数output定义了两个for循环输出Board上的值,时间复杂度为n2;只有棋盘的空间,空间复杂度为1。
所以输出时,算法总的时间复杂度为n4,空间复杂度为n。
调试的时候没有设置define M ,而直接定义棋盘为8*8,调试时等待时间过久,后来先定义M为6,输出正确结果后再定义回8进行验证。
没有在出栈时正确赋值给pos导致程序无法输入结果,后来在pop函数上设置取地址符号才得到正确出栈结果。
没有理解方向d和forward的作用,错误使用两个数据,导致输出的结果只有01没有其他数据,需要将forword和d灵活运用在算法中指示方向并正确的出栈入栈保存数据,为棋子正确行走和棋盘正确赋值。
调试时候栈的长度设置为8,无法输出结果,64时能输出部分结果,经过测试,栈要在100以上才能输出较多结果,因此定义为int类型的最大值2147483647。方便进行棋子在棋盘正中栈较多时进行运算。