"迷宫问题(栈)"

       “栈”是一种简单的数据结构,它的主要特点就是"先进后出",即就是先压入栈中的数据需要最后出栈。相当于栈是一个杯子,最先放进栈中的东西,只能够最后拿出来。下面对“栈”的特点用图形象的表示出来。

        wKiom1cLireC60lEAAAM9HaxAOU999.png

           这次所要讨论的是基于栈的迷宫问题,当给定一个迷宫,我们怎样能够找出迷宫中的通道呢?如果迷宫的规模比较大,我们又该如何去实现呢?我们能够明显的知道需要使用一个二维数组用来保存迷宫,但是当迷宫的规模比较大时,或者是当我们想要频繁的去更改所设计的迷宫时,用二维数组的方式显然是不大合理,程序更改会比较麻烦。


          在这里我采用“文件”的方式将迷宫进行保存,程序中只用实现读取文件的操作,这样很便于以后对程序的维护。因为动态的给定迷宫大小,程序的实现还是较为麻烦的,这里直接将迷宫的规模给定。用“1”来表示不能够通过,“0”表示能够通过。下面是迷宫的设计:

wKiom1cLkC3yqYOtAAAKbBXam2k534.png


        针对迷宫的特点,主要采用的方法是先将迷宫的入口点压入栈中,在对这个点的上、下、左、右方向的节点进行判断,看是否有能够通过的节点(“0”),若没有,则迷宫中没有一条能够通过的路径,如果存在,则将这个节点也压入栈中,循环这种方式,直到找到没有能够前进的点,此时就要进行“回溯”, 即就是倒回以前走过的点。进而在判断有没有刚才没有走过的且能够通过的节点,若存在,再次进行刚才的压栈操作,直到走出迷宫,若回到迷宫的入口点,则迷宫中不存在通路。

       根据上面的思路,编写出下面的代码:


//memory.h文件

#pragma once
#define MAX 10
#include <stack>
#include <assert.h>

//使用静态数组
struct pos     //标记点的位置坐标
{
   int _row;
   int _col;
};

void GetMaze(int * arr, int n)      //从文件中获取迷宫
{
   assert(arr);
   FILE* open = fopen("F:\\keshe\\迷宫问题(栈)\\MazeMap.txt", "r");
   assert(open);    //判断打开文件是否成功
   for (int i = 0; i < MAX; i++)
   {
      for (int j = 0; j < MAX; )
     {
        char ch = fgetc(open);
        if (ch == '1' || ch == '0')
        {
           arr[i * n + j] = ch - '0';
           j++;                            //为了防止迷宫中行与列之间的间距
         }
      }
   }
   fclose(open);
}

void print(int * arr, int n)      //打印迷宫
{
   for (int i = 0; i < MAX; i++)
   {
      for (int j = 0; j < MAX; j++)
      {
         cout << arr[i * n + j] << " ";
       }
      cout << endl;
   }
}

bool checkIsAccess(int * arr, int n, const pos& next)  //检查迷宫节点的下一个路径上的节点
{
    assert(arr);
    if (next._row >= 0 && next._row < MAX && next._col >= 0 && next._col <= MAX
         && arr[next._row * n + next._col] == 0)
    {
       return true;
    }
    return false;
}

//entry 为入口的位置,Paths用来保存迷宫的通路
//判断迷宫中是否存在一条通路
bool SearchMazePaths(int * arr, int n, pos entry, stack<pos> & Paths)  
{
    assert(arr);
    Paths.push(entry);
    while (!Paths.empty())
   {
      pos cur = Paths.top();
      arr[cur._row * n + cur._col] = 2;    //将压栈后的位置内容进行更改
      if (cur._row == (n - 1))
      {
         return true;
      }
      pos next = cur;
      
      //上
      next._row--;
      if (checkIsAccess(arr, n, next))
      {
          Paths.push(next);
          continue;
      } 
      
     //下
     next = cur;
     next._row++;
     if (checkIsAccess(arr, n, next))
     {
         Paths.push(next);
         continue;
     }
     
     //左
     next = cur;
     next._col--;
     if (checkIsAccess(arr, n, next))
     {
        Paths.push(next);
        continue;
     }
     
     //右
     next = cur; 
     next._col++;
     if (checkIsAccess(arr, n, next))
     {
        Paths.push(next);
        continue;
     }
     Paths.pop();     //若节点的剩余方向都不能通过,则进行回溯。
   }
}
//test.cpp文件

#define _CRT_SECURE_NO_WARNINGS 1
//使用栈来设计迷宫问题
#include <iostream>
using namespace std;
#include <stdlib.h>
#include "memory.h"

int main()
{
    int arr[MAX][MAX] = { 0 };
    stack<pos> Paths;
    pos tmp;
    tmp._row = 2;
    tmp._col = 0;
    
    GetMaze((int*)arr, MAX);
    print((int*)arr, MAX);
    cout << endl << endl;
    
    int ret = SearchMazePaths((int *)arr, MAX, tmp, Paths);
    printf("能否有一条通路:%d\n\n\n", ret);
    print((int*)arr, MAX);
    
    system("pause");
    return 0;
}