1. 程式人生 > >資料結構:棧和佇列-迷宮問題求解

資料結構:棧和佇列-迷宮問題求解

//--------------------檔名:Maze.cpp------------------------
//----------------------By SunxySong-------------------------
//說明:本程式以迷宮問題進行演示,瞭解棧和連結串列的資料結構.
//執行過程:隨機生成迷宮地圖(由於未詳細設計演算法,故地圖較簡單),
//         並演示找到出口路徑的過程.
////////////////////////////////////////////////////////////
//主要演算法思想:
// 1.初始化迷宮,構造輔助執行棧和結果連結串列
// 2.從入口開始
// do
// {
//  if (當前位置可通)
//  {
//   當前位置入棧
//   if (當前位置是出口)
//   {
//    結束
//   }
//   else
//   {
//    取得當前位置當前方向上的下一位置為當前位置
//    將新當前位置入棧
//   }
//  }
//  else
//  {
//   從棧中彈出棧頂元素為當前位置
//   while(當前位置已無下一有效位置 && 棧不為空)
//   {
//    將當前位置標記為無效
//    彈出棧頂元素為當前位置
//   }
//   if (當前位置還有下一有效位置時)
//   {
//    當前位置方向調整
//    當前位置進棧
//    取得取得當前位置當前方向上的下一位置為當前位置
//   }
//  }
// }while(棧不為空時);
// 未找到出口
// 3.生成新地圖
// 4.顯示地圖
//////////////////////////////////////////////////////////////
//原始碼在VC6+WIN2000sp2下編譯通過

#include "stdafx.h"
#include <windows.h>
#include <stdlib.h>
#include <iostream>
#include <string>
#include <list>
#include <stack>
#include <time.h>

using namespace std;


//class:MazePos-----------------------------------------
//迷宮通道塊型別
class MazePos
{
public:
 int wx,ly; //塊的X,Y座標 
 int path; //塊的型別;0:空塊,-1:牆壁,1:出口路徑
 bool pass; //是否曾經過(對牆壁無意義);false:沒有,true:曾經過
 bool operator==(const MazePos pos)
 {
  return (wx==pos.wx && ly==pos.ly );
 };
 MazePos operator=(const MazePos pos)
 {
  
  wx=pos.wx;
  ly=pos.ly;
  pass=pos.pass;
  path=pos.path;
  return *this;
 };
};
//End:MazePos---------------------------------------


//class:SElemType-----------------------------------------
//輔助棧元素型別
class SElemType
{
public:
 int ord; //迷宮通道塊路徑上的序號
 MazePos seat;  //通道塊在迷宮中的位置座標
 int di;  //從此通道塊走向下一通道塊的方向
    //0:無效,1:東,2:南,3:西,4:北
 bool operator==(const SElemType et)
 {
  return (seat==et.seat); 
 };
 SElemType operator=(const SElemType et)
 {
  ord =et.ord ;
  seat =et.seat ;
  di =et.di ;
  return (*this);
 };
};
//End:SElemType--------------------------------------


//struct:MazeMap-------------------------------------
//由通道塊組成的迷宮地圖
#define MAPWIDTH 10
#define MAPHEIGHT 10

typedef struct MazeMap
{
 //由通道塊矩陣構成
 MazePos mazemap[MAPWIDTH][MAPHEIGHT];
}MazeMap;
//End:MazeMap---------------------------------------


//struct::MazeWay----------------------------------------
//輔助出口路徑連結串列元素型別
typedef struct MazeWay
{
 int wx,ly;
}MazeWay;
//End:MazeWay--------------------------------------------


//Class:Maze----------------------------------------
//主體類,迷宮路徑問題求解
class Maze
{
public:
 Maze(int width=MAPWIDTH,int height=MAPHEIGHT); //生成迷宮地圖
 ~Maze();
 void DoMaze(); //找出出口路徑並顯示
private:
 bool InitOK; //初始化成功標誌
 MazeMap map; //迷宮地圖
 MazePos start,end; //迷宮的入口和出口
 bool FindPath(); //主要函式,尋找出口路徑
 list<MazeWay> mazeway; //存放出口路徑的臨時連結串列
 void RandMap(); //隨機生成迷宮地圖函式
 bool CreateMap(bool init); //在初始和找到出口路徑後生成相應地圖函式
 bool pass(MazePos curpos); //當前路徑通道塊是否可通(即是不是未經過的空塊)
 MazePos NextPos(MazePos curpos,int di); //取得當前通道塊當前方向上的下一個通道塊
 bool Invalide(SElemType e); //使當前通道塊標記為不可通
 void DisplayMaze(); //顯示迷宮地圖

};

Maze::Maze(int width,int height)
{
 //
 //隨機生成迷宮地圖
 CreateMap(true);
 //顯示地圖
 DisplayMaze();
}

Maze::~Maze()
{
 //Add codes here
}

bool Maze::FindPath ()
{
 //
 //尋找出口,並生成出口路徑連結串列
 if(InitOK)
 {
  //MazeStack mstack;
  stack<SElemType,list<SElemType> > mstack;
  MazePos curpos=start;
  int curstep=1; //經過的步數
  MazeWay mw; //出口路徑塊元素
  unsigned mwsize=mazeway.size (); //為顯示執行過程而設
  do
  {
   if(pass(curpos))
   {
    //如果當前位置可通(即是未走過的空塊)

    //封裝棧元素,將當前位置進棧
    SElemType e;
    e.ord =curstep;
    e.seat =curpos;
    e.di =1;
    mstack.push (e);

    //儲存當前位置到出口路徑連結串列
    mw.wx =e.seat .wx ;
    mw.ly =e.seat .ly ;
    mazeway.push_back (mw);


    //如果是出口,則結束
    if(curpos==end)
     return true;

    //不然就將得到下一個通道塊
    curpos=NextPos(curpos,e.di );
    curstep++;
   }
   else
   {
    //當前位置不可通,則在棧內找到下一個位置
    if(!mstack.empty())
    {
     SElemType e;
     e=mstack.top ();
     mstack.pop ();
     
     //調整出口路徑連結串列
     mazeway.pop_back ();

     while((e.di==0 || e.di ==4) && !mstack.empty ())
     {
      Invalide(e);  //標記刻通道塊不能通過
      e=mstack.top ();
      mstack.pop (); //退回一步

      //調整出口路徑連結串列
      mazeway.pop_back ();

     }
     if(mstack.empty ())
      return false;
     else if( e.di<5)
     {
      e.di++;
      e.di=e.di%5;

      mstack.push (e);

      //儲存當前位置到出口路徑連結串列
      mw.wx =e.seat .wx ;
      mw.ly =e.seat .ly ;
      mazeway.push_back (mw);

      curpos=NextPos(e.seat ,e.di );
     }
     
    }
   }
   ///*//顯示執行過程
   if(mwsize!=mazeway.size () )
   {
    CreateMap(false);
    DisplayMaze();
    mwsize=mazeway.size ();
    Sleep(800); //要包含windows.h標頭檔案
   }
   //*
  }while(!mstack.empty ());
 }
 return false;
}

MazePos Maze::NextPos(MazePos curpos,int di)
{
 //
 MazePos pos;
 switch(di)
 {
 case 1:
  pos=map.mazemap [curpos.wx+1][curpos.ly ] ;
  break;
 case 2:
  pos=map.mazemap [curpos.wx][curpos.ly+1 ] ;
  break;
 case 3:
  pos=map.mazemap [curpos.wx-1][curpos.ly] ;
  break;
 case 4:
  pos=map.mazemap [curpos.wx][curpos.ly-1] ;
  break;
 }
 return pos;
}

bool Maze::pass(MazePos curpos)
{
 //
 //通過MazePos型別引數傳遞的資訊檢查MazeMap map;
 if(curpos.wx <0 ||
  curpos.wx >=MAPWIDTH ||
  curpos.ly <0 ||
  curpos.ly >=MAPHEIGHT)
  return false;
 return (map.mazemap [curpos.wx ][curpos.ly ].path ==0 &&
   map.mazemap [curpos.wx ][curpos.ly ].pass ==false );
 
}

void Maze::DoMaze ()
{
 //
 if(!InitOK)
  return;
 if(FindPath())
 {
  CreateMap(false);
  DisplayMaze();
 }
 else
 {
  cout<<endl<<"NO PATH!"<<endl;
 }
}

void Maze::RandMap ()
{
 //
 //只能生成從左上到右下的迷宮地圖
 MazeWay curway; //隨機生成的當前正處理的出口路徑塊(組成mw)
 list<MazeWay> mw; //隨機生成的出口路徑(由curway組成)
 list<MazeWay>::iterator iter; //容器介面卡

 curway.wx =0;
 curway.ly =1;
 mw.push_back (curway);

 curway.wx ++;
 mw.push_back (curway);

 srand(time(0)); //取得當前時間作為隨機數種子

 while(curway.wx <MAPWIDTH-1 && curway.ly <MAPHEIGHT-1)
 {
  if(rand()%2==1)
  {
   //生成隨機X座標上的路徑塊
   curway.wx ++;
   
   mw.push_back (curway);
  }
  else
  {
   //生成隨機Y座標上的路徑塊
   curway.ly ++;
   mw.push_back (curway);
  }
 }

 srand(time(0));
 for(int y=0;y<MAPHEIGHT;y++)
 {
  for(int x=0;x<MAPWIDTH;x++)
  {
   //填充每個通道塊
   map.mazemap [x][y].wx =x;
   map.mazemap [x][y].ly =y;
   map.mazemap [x][y].pass =false;
   if(x==0||y==0||x==MAPWIDTH-1||y==MAPHEIGHT-1)
   {
    //生成四周牆壁
    map.mazemap [x][y].path =-1;
    //map.mazemap [x][y].pass =true;
   }
   else
   {
    if(rand()%10>=6) //數值越小,牆壁越多
    {
     map.mazemap [x][y].path =-1; //隨機生成牆壁
     //map.mazemap [x][y].pass =true;
    }
    else
    {
     map.mazemap [x][y].path =0; //生成空的通道塊
     //map.mazemap [x][y].pass =false;
    }
   } 
  }
 }
 //生成出口路徑
 for(iter=mw.begin ();iter!=mw.end ();iter++)
 {
  map.mazemap [(*iter).wx ][(*iter).ly ].path =0;
  //map.mazemap [(*iter).wx ][(*iter).ly ].pass =false;
 }
 //生成入口和出口

 start=map.mazemap [mw.front ().wx][mw.front ().ly];
 end=map.mazemap [mw.back ().wx][mw.back ().ly];
 //初始化成功
 InitOK=true;
}

bool Maze::CreateMap (bool init)
{
 //
 if(init)
 {
  RandMap();
 }
 else
 {
  for(int y=0;y<MAPHEIGHT;y++)
   for(int x=0;x<MAPWIDTH;x++)
   {
    if(map.mazemap [x][y].path ==0)
     map.mazemap [x][y].pass =0;
   }
  list<MazeWay>::iterator  iter;
  for(iter=mazeway.begin ();iter!=mazeway.end ();iter++)
  {
   map.mazemap [(*iter).wx][(*iter).ly ].path =1;
  }
 }
 return true;
}

bool Maze::Invalide (SElemType e)
{
 //
 //通過SElemType型別引數傳遞的資訊修正MazeMap map;
 if(e.seat .wx<0 ||
  e.seat .wx>=MAPWIDTH ||
  e.seat .ly<0 ||
  e.seat .ly>=MAPHEIGHT)
  return false;
 map.mazemap [e.seat .wx][e.seat .ly ].pass =true;
 return true;
}

void Maze::DisplayMaze ()
{
 //
 cout<<endl;
 for(int y=0;y<MAPHEIGHT;y++)
 {
  for(int x=0;x<MAPWIDTH;x++)
  {
   switch (map.mazemap [x][y].path)
   {
   case -1:
      cout<<"█";break; //牆壁圖案
   case 0:
      cout<<"  ";break; //空塊圖案
   case 1:
      cout<<"==";break; //出口路徑圖案
   }
    
  }
  cout<<endl;
 }
 cout<<endl; 
}
//End:Maze----------------------------------------

//main--------------------------------------------
//主函式,迷宮求解演示
int main(int argc, char* argv[])
{
 //
 cout<<"下面是隨機生成的迷宮:"<<endl;
 Maze mymaze; //生成迷宮
 cout<<"按任意鍵演示迷宮解法!"<<endl;
 system("pause");
 mymaze.DoMaze (); //生成出口路徑
 cout<<"演示結束."<<endl;
 system("pause");
 return 0;
}
//End:main--------------------------------------------

下圖為演示抓圖

相關推薦

資料結構:佇列-迷宮問題求解

//--------------------檔名:Maze.cpp------------------------//----------------------By SunxySong-------------------------//說明:本程式以迷宮問題進行演示,瞭解

資料結構 - 佇列

資料結構 - 棧和佇列 介紹 棧和佇列是兩種很簡單, 但也很重要的資料結構, 在之後的內容也會用到的

資料結構---佇列結構體實現)

棧(LIFO) 棧(stack)是一種只能在一端進行插入或刪除操作的線性表。 棧頂(top):允許進行插入、刪除操作的一端 棧底(bottom):另一端稱為棧底 進棧或入棧(push):插入操作 出棧或退棧(pop):棧的刪除操作 n個不同元素通過一個棧產生的出棧

資料結構---佇列(例題、練習及解答)

棧的應用 Q1:簡單表示式求值 限定的簡單表示式求值問題是使用者輸入一個包含+、-、*、/、正整數和圓括號的合法算術表示式,計算該表示式的結果。 思路:(1)將算術表示式轉換成字尾表示式 (2)字尾表示式求值 具體執行程式碼: #include <

資料結構——佇列

棧和佇列 一、選擇題 ~~01|03|1|1 ^^設有一個遞迴演算法如下 int fact(int n) { //n大於等於0 if(n<=0) return 1; else return n*fact(n-1); } 則計算fact(n)

資料結構佇列、遞迴演算法

知識要點: 棧的定義、結構特點及其儲存方式(順序儲存與連結儲存)和基本操作的實現演算法; 佇列的結構、特點及其儲存方式(順序儲存與連結儲存)和基本操作的實現演算法。 遞迴的基本概念和實現原理以及用遞迴的思想描述問題和書寫演算法的方法; 用棧實現遞迴問題的非遞迴解法。

資料結構 佇列

文章目錄 1 棧 1.1 抽象資料型別棧的定義 1.1.1 棧頂和棧尾 1.1.2 空棧 1.1.3 特點 1.1.4 上溢和下溢 1.2 棧的表示和實現 1.2.1

資料結構佇列(五)的順序儲存結構鏈式儲存結構的實現

一、 實驗目的1. 熟悉棧的特點(先進後出)及棧的抽象類定義;2. 掌握棧的順序儲存結構和鏈式儲存結構的實現;3. 熟悉佇列的特點(先進先出)及佇列的抽象類定義;4. 掌握棧的順序儲存結構和鏈式儲存結構的實現;二、實驗要求1. 複習課本中有關棧和佇列的知識;2. 用C++語言

還債系列之資料結構——佇列

三、棧 還記得當初第一次學習程式設計的時候還是8051微控制器中的組合語言,現在還記得很清楚,當初遇到的一個簡單的資料結構就是——棧,對應的組合語言中的命令是push和pop。這個結構在生活中是有很多類似的例子的,比如水杯、碗等。該結構的特點如下: 最大特

資料結構-佇列面試題(下)

面試題四:元素出棧、入棧順序的合法性。如入棧的序列(1,2,3,4,5),出棧序列為(4,5,3,2,1)。 思路: ①首先判斷出棧入棧序列長度是否一致,不一致直接返回false; ②借用一個臨時的棧,依次遍歷入棧序列的每一個元素,每次

資料結構 佇列 演算法設計題

五 演算法設計題 1. 設有兩個棧S1,S2都採用順序棧方式,並且共享一個儲存區[O..maxsize-1],為了儘量利用空間,減少溢位的可能,可採用棧頂相向,迎面增長的儲存方式。試設計S1,S2有關入棧和出棧的操作演算法。 【哈爾濱工業大學 2001 七 (12分)】 2

資料結構--佇列的面試題

實現一個棧,要求實現Push(出棧)、Pop(入棧)、Min(返回最小值)的時間 複雜度為O(1) 方法1、棧Push時:當棧為空時,push兩次第一個資料。棧頂的數來儲存當前狀態的最小值。 再次Push資料時候,先拿將要Push的資料與棧頂的最小值進行比較,更

資料結構-佇列小結

1棧   1>棧的定義:       棧是限定僅在表尾進行插入和刪除操作的線性表。       我們把插入和刪除的一端稱為棧頂(TOP),另一端稱為棧底(BOTTOM),不包含任何元素的棧稱為空棧。棧又稱為後進先出(Last in first out)的線性表,簡稱L

資料結構-佇列——20150602

//順序棧定義及實現 #include<stdio.h> #include<malloc.h> #include<stdlib.h> //函式結果狀態程式碼 #define TRUE 1 #define

資料結構-佇列面試題(上)

在資料結構的學習過程中,棧和佇列的掌握是十分重要的。所以找了幾個很熱門的面試題試試手並小結一下。先回顧下棧和佇列的特性:棧是後進先出,主要介面有PUSH,POP,TOP,而佇列是先進先出,主要介面有PU

C資料結構-佇列,括號匹配舉例---ShinePans

1.棧和佇列是兩種特殊的線性表             運算操作被限定只能在表的一端或兩端插入,刪除元素,故也稱它們為限定的線性表結構 2.棧的基本運算 1).Stackinit(&s) 構造一個空棧 2).Stackempty(s) 判斷s是否為空棧,當s為空棧

資料結構-佇列

                  &n

線性結構 -- 佇列

線性結構 – 棧和佇列 線性結構是一個有序資料元素的集合。 常用的線性結構有:線性表,棧,佇列,雙佇列,陣列,串。 常見的非線性結構有:二維陣列,多維陣列,廣義表,樹(二叉樹等),圖。 特徵: 1.集合中必存在唯一的一個"第一個元素"; 2.集合中必存在唯一的一個"最後的元素

資料結構-佇列

棧的定義 棧是限定僅在表尾進行插入和刪除操作的線性表 我們把允許插入和刪除的一端稱為棧頂 (top) ,另一端稱為棧底 (bottom) ,不含任何資料元素的棧稱為空棧。 棧又稱為後進先出 (Last In Filrst Out) 的線性表,簡稱LIFO結構。 理解棧的定義需要注意:

資料結構--佇列

一、定義 1、棧的操作   注意:棧的插入和刪除改名叫push和pop   2、棧的順序儲存結構和實現 1)進棧操作 2)出棧的操作 3、兩棧共享空間 注意: