数据结构课程设计:迷宫问题(一)

一、实验要求:

  • 问题描述
    以一个m*n的长方阵表示迷宫,0和1分别表示迷宫中的通路和障碍。设计一个程序,对任意设定的迷宫,求出一条从入口到出口的通路,或得出没有通路的结论。
  • 基本要求
    • 实现一个以链表作存储结构的栈类型,然后编写一个求解迷宫的非递归程序。求得的通路以三元组(i,j,d)的形式输出,其中:(i,j)指示迷宫中的一个坐标,d表示走到下一坐标的方向。
    • 编写递归形式的算法,求得迷宫中所有可能的通路;
    • 方阵形式输出迷宫及其通路

二、结构框架:

图1

三、代码

主函数

在这里插入图片描述

int main()
{
	//初始化迷宫 
	cout<<("这是一个m行n列,以左上角为起点,右下角为终点的迷宫")<<endl;
	cout<<("\n请输入迷宫的行和列数:")<<endl;
	cin>>m>>n;
	int **maze=new int *[m+2];
    for(int i=0;i<m+2;i++){
        maze[i]=new int[n+2];
    }
     //在迷宫四周增加障碍墙 
    for(int i=0;i<m+2;i++){
        maze[i][0]=maze[i][n+1]=1;
    }
    for(int i=0;i<n+2;i++){
        maze[0][i]=maze[m+1][i]=1;
    }
	cout<<("请选择迷宫生成方式:0随机产生,1手动输入")<<endl;
	cin>>choice;
	if(choice){
		while(flag) initMaze(maze);
	} 
	else createMaze(maze); 
	//利用栈求通路并以三元组形式输出 
	cout<<("\n用栈实现深度优先搜索求得通路:")<<endl; 
	dfsFindPath(maze);
	cout<<("\n用栈实现宽度优先搜索求最短路:")<<endl;
	bfsFindPath(maze);
	//递归求得所有通路并自选形式输出 
	if(flag){
		cout<<("\n递归求得迷宫中所有可能的通路:")<<endl;
		allPaths(maze,1,1);
	}
	cout<<"以上是全部路径"; 
	//system("pause");
	return 0;
}
PartⅠ.以链表作为存储结构的栈操作

在这里插入图片描述

struct position
{
	int row,col;
	int direction;
};
struct node
{
	position data;
	node *next;
};
class stack
{
	private:
		int StackSize;
		node *StackTop;
	public:
		stack():StackSize(0),StackTop(NULL){};
		~stack();
		bool empty() const{ return StackSize==0; }
		int size() const{ return StackSize; }
		position top(){
			if(StackSize==0){
				cout<<"empty stack"<<endl;
			}
			else return StackTop->data;
		}
		node* topNode(){//便于栈的输出
			if(StackSize==0) cout<<"empty stack"<<endl;
			else return StackTop;
		}
		void pop();
		void push(position onePosition){
			node *p=new node;
			p->data=onePosition;
			p->next=StackTop;
			StackTop=p;
			StackSize++;
		}
	friend  ostream& operator<<(ostream& output,stack &s); 
};
stack::~stack()
{
    node *p;
    while(StackTop){
        p=StackTop->next;
        delete StackTop;
        StackTop=p;
    }
    StackSize=0;
}
void stack::pop()
{
	if(empty()){
		cout<<("empty stack")<<endl;
		return;
	}
	node *p=StackTop;
	StackTop=StackTop->next;
	delete p;
	StackSize--;	
}
ostream& operator<<(ostream& output,stack &s)//重载运算符实现三元组形式输出
{
       if(s.empty()){
            output<<"empty stack"<<endl;
       }
       else{
            node *p=s.topNode();
            while(p){
             	output<<"("<<p->data.row<<","<<p->data.col<<",";
                switch(p->data.direction){
           	       case 0:
                		output<<"→"<<")\n";break;
            	   case 1:
                		output<<"↓"<<")\n";break;
            	    case 2:
               	 	 	output<<"←"<<")\n";break;
            	    case 3:
               			output<<"↑"<<")\n";break;
                    case 4:
                		output<<"★"<<")\n";break;
            	   }
                p=p->next;
            }

       }
       return output;
}

int dRow[4]={0,1,0,-1},dCol[4]={1,0,-1,0};//右、下、左、上

Part Ⅱ.初始化迷宫

1.手动输入:

void initMaze(int** maze)//创建迷宫
{
//    int **maze=new int *[m+2];
//    for(int i=0;i<m+2;i++){
//        maze[i]=new int[n+2];
//    }
    cout<<"请输入迷宫分布:(用0和1分别表示通路和障碍,以空格分隔)"<<endl;
    for(int i=1;i<=m;i++){
        for(int j=1;j<=n;j++){
		cin>>maze[i][j];
        }
    }
    if(maze[1][1]==1){
	cout<<("抱歉,入口处不可设置障碍物,请重新输入迷宫分布")<<endl;
	return;
    }
    flag=false;
//    //在迷宫四周增加障碍墙 
//    for(int i=0;i<m+2;i++){
//        maze[i][0]=maze[i][n+1]=1;
//    }
//    for(int i=0;i<n+2;i++){
//        maze[0][i]=maze[m+1][i]=1;
//    }
}

2.随机生成(Prim算法)

  • 算法原理:
    (1)初始地图所有位置均设为障碍墙;
    (2)任意插入一个墙体进墙队列;
    (3)判断此时墙体是否可以设置为路(判断依据:上下左右四个位置是否只有一个位置是路);
    (4)若设置为路,则将该位置四周所有的墙插入队列,接着执行(5);若无法设置为路,直接执行(5);
    (5)从墙队列中删去当前位置所在节点;
    (6)若墙队列不为空,则从队列中随机选取一处障碍重新执行(3),直到墙队列为空。
void createMaze(int** MAZE){
	int maze[m+4][n+4];
    for(int i=0;i<m+4;i++){
    	for(int j=0;j<n+4;j++){
    		maze[i][j]=1;
		}	
	}
    //将迷宫四周设为通路,保护障碍墙,防止出界
    for(int i=0;i<m+4;i++){
        maze[i][0]=maze[i][n+3]=0;
    }
    for(int i=0;i<n+4;i++){
        maze[0][i]=maze[m+3][i]=0;
    }
    vector<int> X,Y;
    X.push_back(2);
    Y.push_back(2);
    while (X.size()) {
		//在墙队列中随机取一点
		srand((unsigned int)(time(NULL)));
		int index=rand()%(X.size());
		int x=X[index];
		int y=Y[index];
		//判读上下左右四个方向是否为路
		int count = 0;
		int r,c;
		for(int i=0;i<4;i++){
			r=x+dRow[i];c=y+dCol[i];
			if(maze[r][c]==0)
				count++;
		} 
		if(count<=1){
			maze[x][y]=0;
			for(int i=0;i<4;i++){
				r=x+dRow[i];c=y+dCol[i];
				if(maze[r][c]==1){
					X.push_back(r);
					Y.push_back(c);
				}
			}

		}
		//删除当前墙
		X.erase(X.begin()+index);
		Y.erase(Y.begin()+index);
	}
	for (int i = n- 3; i >= 0; i--) {
		if (maze[i][n - 3] == 0) {
			maze[i][n - 2] = 0;
			break;
		}
	}
	maze[m+1][n+1]=0;
	cout<<"随机生成的迷宫为:"<<endl; 
	for(int i=1;i<=m;i++){
		for(int j=1;j<=n;j++){
			MAZE[i][j]=maze[i+1][j+1];
			cout<<MAZE[i][j]<<" ";
		}
		cout<<endl;
	}
}
Part Ⅲ.利用栈求通路,以三元组形式输出:

①dfs求通路:

void dfsFindPath(int **maze)
{
	stack path;
	position here={1,1,0};
	maze[1][1]=2;
	int option=0;
	while(here.row!=m||here.col!=n){
		//没有到达出口,找要移动的相邻一步
		int r,c;
		while(option<4){//0、1、2、3四个方位 
			r=here.row+dRow[option];
			c=here.col+dCol[option];
			if(maze[r][c]==0)break;
			option++;
		}
		if(option<4){//找到相邻一步 
			here.direction=option;
			path.push(here);
			here.row=r;
			here.col=c;
			maze[r][c]=2;
			option=0;
		}
		else{//邻近没有通路,回溯 
			if(path.empty()){
				cout<<("No path.")<<endl;
				return;
			}
			position prev=path.top();
			path.pop();
			if(prev.row==here.row)
				option=2+prev.col-here.col;
			else option=3+prev.row-here.row;
			here=prev;//回到前一个点走下一步 
		}
	}
	//到达出口将出口入栈以便路径完整输出
	path.push((position){m,n,4}); 
	//利用新栈实现正序输出,并还原maze 
	stack orderedPath;
	while(!path.empty()){
		orderedPath.push(path.top());
		path.pop();
	}
	cout<<orderedPath;
	remaze(maze); 
}

②bfs求最短路

void bfsFindPath(int **maze)
{
	position prePos[m+1][n+1];//记录上一个position
	stack in,out;
	position here,next;
	maze[1][1]=2;
	out.push({1,1,0});//起点入队 
	while(!in.empty()||!out.empty()){
		//出队
		if(out.empty()){
			while(!in.empty()){
				out.push(in.top());
				in.pop();
			}
		}
		here=out.top();
		out.pop();
		if(here.row==m&&here.col==n){//到达出口
			flag=true;
			break;
		}
		for(int i=0;i<4;i++){
			int r=here.row+dRow[i];
			int c=here.col+dCol[i];
			if(maze[r][c]==0){
				maze[r][c]=2;
				here.direction=i;//记录方向 
				prePos[r][c]=here;
				next.row=r;
				next.col=c;
				in.push(nex);//下一个入队 
			}
		}
	}
	if(flag){
		//从终点向起点回溯,此时here.row=m here.col=n 
		stack path;
		path.push({m,n,4});
		while(here.row!=1||here.col!=1){
			here=prePos[here.row][here.col];
			path.push(here);
		}
        //利用栈FIFO思想直接正序输出
		cout<<path;
	}
	else cout<<("No path.");
	remaze(maze);	
}
Part Ⅳ.(DFS)递归求所有通路,以三元组或方阵形式输出:
stack path;
int rank=1;
bool choice;
void printPath();
void printPath(int** maze);
void allPaths(int **maze,int row,int col)
{
	if(row==m&&col==n){
		maze[m][n]=6;
		path.push({m,n,4});
		cout<<"第"<<(rank++)<<"条路径:"<<endl;
		cout<<("请选择输出方式:输入0为三元组形式,1为方阵形式")<<endl;
		cin>>choice;
		if(choice) printPath(maze);
		else printPath();
		maze[m][n]=0;
		path.pop();
		return;
	}
	for(int i=0;i<4;i++){
		int r=row+dRow[i];
		int c=col+dCol[i];
		if(maze[r][c]==0){
			maze[row][col]=i+2;
			path.push({row,col,i});
			allPaths(maze,r,c);
			maze[row][col]=0;
			path.pop();	
		}
	}
}

重载printPath函数,分别实现栈的三元组形式输出和迷宫的方阵形式输出。

void printPath(){
	stack orderedPath;
	node* p=path.topNode();
	while(p){
		orderedPath.push(p->data);
		p=p->next;
	}
	cout<<orderedPath;
}
void printPath(int **maze)
{
	cout<<("注:.代表通路,#代表障碍物,*代表终点")<<endl;
	for(int i=1;i<=m;i++){
		for(int j=1;j<=n;j++){
			if(maze[i][j]==0)
				cout<<". ";	
			else if(maze[i][j]==1)
				cout<<"# ";
			else{
				switch(maze[i][j]-2)
				{
	        		case 0:
	               		cout<<"> ";break;
	            	case 1:
	                	cout<<"V ";break;
	            	case 2:
	               	 	cout<<"< ";break;
	            	case 3:
	               		cout<<"A ";break;
	               	case 4:
	                	cout<<"* ";break;
	            }
			}
		}
		cout<<endl;
	}
}
  • 31
    点赞
  • 200
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 13
    评论
程序在VC++ 6下顺利编译通过。 一、 实验目的: (1) 熟练掌握链栈的基本操作及应用。 (2) 利用链表作为栈的存储结构,设计实现一个求解迷宫的非递归程序。 二、实验内容: 【问题描述】 以一个m×n的方阵表示迷宫,0和1分别表示迷宫通路障碍设计一个程序,对信任意设定的迷宫,求出一条从入口到出口的通路,或得出没有通路的结论。 【基本要求】 首先实现一个链表作存储结构的栈类型,然后编写一个求解迷宫的非递归程序。求得的通路以三元组(i,j,d)的形式输出,其:(i,j)指示迷宫一个坐标,d表示走到下一坐标的方向。如:对于下列数据的迷宫,输出的一条通路为:(1,1,1),(1,2,2),(2,2,2),(3,2,3),(3,1,2),……。 【测试数据】 迷宫的测试数据如下:左上角(1,1)为入口,右下角(8,9)为出口。 1 2 3 4 5 6 7 8 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 0 0 1 1 0 1 0 1 1 1 0 0 1 0 0 0 0 1 0 0 0 0 0 1 0 0 0 1 0 1 0 1 1 1 1 0 0 1 1 1 0 0 0 1 0 1 1 1 0 0 0 0 0 0 以方阵形式输出迷宫及其通路。 输出: 请输入迷宫和宽:5 5 请输入迷宫内容: 0 1 1 0 0 0 0 1 1 0 1 0 0 1 1 1 0 0 1 0 1 1 0 0 0 迷宫的路径为 括号内的内容分别表示为(行坐标,列坐标,数字化方向,方向) (1,1,1,↓) (2,1,2,→) (2,2,1,↓) (3,2,1,↓) (4,2,2,→) (4,3,1,↓) (5,3,2,→) (5,4,2,→) (5,5,0,) 迷宫路径探索成功!
迷宫问题一个经典的数据结构课程设计问题,目标是设计一个算法,找到从迷宫的起点到终点的路径。迷宫可以用一个方阵[m,n]表示,其0表示可以通过的路径,1表示不可通过的路径。我们需要从左上角[1,1]进入迷宫,寻找一条从右下角[m,n]出去的路径。 以下是一个可能的解决方案: 1. 使用深度优先搜索算法(DFS): - 创建一个空的路径列表,用于存储找到的路径。 - 创建一个空的访问列表,用于记录已经访问过的位置。 - 定义一个递归函数,该函数接受当前位置和当前路径作为参数。 - 在递归函数,首先检查当前位置是否为终点,如果是,则将当前路径添加到路径列表并返回。 - 如果当前位置不是终点,则将当前位置添加到访问列表,并继续向四个方向进行探索。 - 对于每个可行的方向,递归调用函数,并将当前位置和路径作为参数传递。 - 在递归调用返回后,将当前位置从访问列表移除。 - 最后,返回路径列表的第一条路径作为结果。 2. 使用广度优先搜索算法(BFS): - 创建一个空的路径列表,用于存储找到的路径。 - 创建一个空的队列,用于存储待探索的位置。 - 创建一个空的访问列表,用于记录已经访问过的位置。 - 将起点位置添加到队列,并将其标记为已访问。 - 进入循环,直到队列为空: - 从队列取出一个位置。 - 检查该位置是否为终点,如果是,则将路径添加到路径列表并继续下一次循环。 - 如果该位置不是终点,则将其标记为已访问,并将其可行的相邻位置添加到队列。 - 返回路径列表的第一条路径作为结果。 这两种算法都可以用来解决迷宫问题,具体选择哪种算法取决于实际需求和迷宫的规模。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

宅女不减肥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值