數據結構和算法設計(迷宮求解問題的棧和隊列的實現)

此問題中,迷宮用一個二位數組data[ ][ ]表示,data[i][j]的值爲0,則表示該點爲通路;如果爲1,則表示該點爲障礙;如果爲-1,則表示該點已經走過。數組的四周值都爲1,表示邊界。給定起點和終點,求起點到終點的路徑。

可以使用棧對二維數組進行深度優先搜索,直到找到終點的時候停止搜索。此方案找到的路徑不一定是最短路徑。如果要好到最短路徑,可以使用隊列來進行二維數組的寬度優秀搜索,直到找到終點停止搜索,然後從隊列中找出我們需要的最短路徑。廢話少說,代碼如下:

import java.util.ArrayList;
import java.util.List;
import java.util.Stack;

public class Maze {
private int[][] data = null;//數據1:障礙,0:出路,-1:此點已經通過
private Stack<Point> stack = new Stack<Point>() ;
private List<Point> queue = new ArrayList<Point>() ;//用數組模擬隊列操作

public Maze(int[][] data){   //出使化
this.data = data ;
}

public boolean getPath(Point start , Point end){
boolean isFind = false ;//是否找到
Point temp = null;

stack.push(start) ;//將起點入棧
this.data[start.getX()][start.getY()] = -1 ;//起點標記爲走過
while(!stack.isEmpty()){//棧不爲空時進入循環

temp = stack.lastElement() ;//得到棧頂元素
int x = temp.getX() ;
int y = temp.getY() ;
int di = temp.getDirection() ;//得到方向

if(temp.equals(end)){//找到終點
printPath() ;
return true ;
}

isFind = false ;
while(di<4 && !isFind){//當方向沒有找完,而且沒有找到
di++ ;//下一個方向尋找
switch(di){
case 0: x = temp.getX() - 1 ; y = temp.getY() ; break ;//向上
case 1: x = temp.getX() ; y = temp.getY() + 1 ; break ;//向右
case 2: x = temp.getX() + 1 ; y = temp.getY() ; break ;//向下
case 3: x = temp.getX() ; y = temp.getY() - 1 ; break ;//向左
default : break ;
}
if(this.data[x][y] == 0){//如果找到則跳出循環
isFind = true ;
}
}

if(isFind){//如果找到了出路,則將此節點入棧
stack.lastElement().setDirection(di) ;//設置上一個節點的方向
Point p = new Point(x , y , -1) ;//新節點入棧
stack.push(p) ;
this.data[x][y] = -1 ;//將當前節點標記爲障礙
}else{//如果沒有找到節點 
Point p = stack.pop() ;//出棧
this.data[p.getX()][p.getY()] = 0 ;//當前節點標記爲通路
}
}
return false ;
}

public boolean getPath2(Point start, Point end){//使用隊列找到起點到終點的最短路徑
int index = -1 ;//隊列中下標值 
Point temp = null ;
boolean isFind = false ;
int x=-1 , y=-1 , di=-1 ;

queue.add(start) ;//起點入隊列
this.data[start.getX()][start.getY()] = - 1 ; //起點標記爲走過
while(!queue.isEmpty() && !isFind){
index++ ;
temp = queue.get(index) ;//得到隊列中尋找的節點
if(temp.equals(end)){
printPath2(index) ;//index爲終點在隊列中的下標值
return true ;
}

isFind = false ;
for(di = 0 ; di<4 ; di++){
switch(di){
case 0: x = temp.getX() - 1 ; y = temp.getY() ; break ;//向上
case 1: x = temp.getX() ; y = temp.getY() + 1 ; break ;//向右
case 2: x = temp.getX() + 1 ; y = temp.getY() ; break ;//向下
case 3: x = temp.getX() ; y = temp.getY() - 1 ; break ;//向左
default : break ;
}

if(this.data[x][y] == 0){//節點是通路
queue.add(new Point(x , y , index)) ;
this.data[x][y] = -1 ;//將此點標記爲走過
}
}
}
return false ;
}

public void printPath(){
for(int i=0 ; i<stack.size() ; i++){
Point p = stack.get(i) ;
System.out.println("[" + p.getX() + "," + p.getY() + "]");
}
}

public void printPath2(int x){
int index = x ;//終點在隊列中的下標
while(index != -1){
int pre = queue.get(index).getDirection() ;//得到前一個點的下標
queue.get(index).setDirection(-1) ;//將我們需要的路徑上的點的前驅置爲-1
index = pre ;
}

for(int i=0,len=queue.size() ; i<len ; i++){
Point p = queue.get(i) ;
if(p.getDirection() == -1){
System.out.println("[" + p.getX() + "," + p.getY() + "]");
}
}
}

public static void main(String[] args) {
int mg[][] =       //定義迷宮,0代表通路,1代表障礙
{ {1,1,1,1,1,1,1,1,1,1},
{1,0,0,1,0,0,0,1,0,1},
{1,0,0,1,0,0,0,1,0,1},
{1,0,0,0,0,1,1,0,0,1},
{1,0,1,1,1,0,0,0,0,1},
{1,0,0,0,1,0,0,0,0,1},
{1,0,1,0,0,0,1,0,0,1},
{1,0,1,1,1,0,1,1,0,1},
{1,1,0,0,0,0,0,0,0,1},
{1,1,1,1,1,1,1,1,1,1} };
Maze m = new Maze(mg) ;
Point p1 = new Point(1 , 1 ) ;
Point p2 = new Point(8 , 8 ) ;
// m.getPath(p1 , p2) ;
m.getPath2(p1 , p2) ;
}
}


在此類中用到了一個輔助類Point,代碼如下:

package edu.qc.stack;


public class Point {
private int x;
private int y;
private int direction;//如果使用棧,此變量代表從此點經過時候的方向,0:上,1:右,2:下,3:左;如果使用隊列,則此變量代表路徑中此點的前一個節點在隊列中的下標值

public Point(){
this.x = 0 ; 
this.y = 0 ;
this.direction = -1 ;
}

public Point(int x , int y){
this.x = x ;
this.y = y ;
this.direction = -1 ;
}

public Point(int x , int y , int direction){
this.x = x ;
this.y = y ;
this.direction = direction ;
}


public int getX() {
return x;
}


public void setX(int x) {
this.x = x;
}


public int getY() {
return y;
}


public void setY(int y) {
this.y = y;
}


public int getDirection() {
return direction;
}


public void setDirection(int direction) {
this.direction = direction;
}


@Override
public boolean equals(Object obj) {
if(obj instanceof Point){
Point p = (Point)obj ;
if((p.getX() == this.x) && (p.getY() == this.y)){
return true ;
}else{
return false ;
}
}
return false ;
}


@Override
public int hashCode() {
return super.hashCode() + x + y;
}
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章