1. 程式人生 > >java自定義棧實現簡單迷宮

java自定義棧實現簡單迷宮

package stack;



import stack.sq.SqStack;
/**
 * 
 * @author 半步瘋子
 * 通過迷宮求解,其中出錯的問題就是對引用型別變數的理解不夠深刻
 * 傳值和傳地址不夠明確
 * 即使我的引用型別變數被壓入棧中,但是我的curpos指向的同樣還是對應e中的seat的物件
 * 所以這裡不能在原來的nextPos方法上進行修改,修改了之後棧中前一步的position也跟著改變了
 * 如果當前步(curpos)不是可通過的區域,那麼就會pop到上一步,但是上一步已經被修改到和
 * 當前位置相同的position了,所以就會造成對角線可通過的情況(因為當前是站在牆“1”上的)
 * 0 1 1 1 1 
 * 1 0 1 1 1(對角線通過,兩個0通過;但是迷宮規則,對角線是不能通過的)
 */
public class StackSolveMaze {
	
	/**
	 * 位置座標
	 * @author Administrator
	 * 
	 */
	private class Position {
		// 非靜態內部類中不能放靜態的欄位 static x static y
		/*
		 * int x;
		 * int y;
		 * 這裡的x和y與傳統意義上的x和y不同
		 * 為了避免混淆,用row和loc的點定義
		 * 這裡的x等價於row(行)
		 * 這裡的y等價於col(列)
		 * 行號x和列號y剛好與傳統的x、y相反
		 * 
		 */
		int row; 
		int col;
	}

	/**
	 * 棧中的元素型別
	 * @author Administrator
	 * 
	 */
	private class StackElem {
		int ord; // 通道塊在路徑上的 序號
		Position seat; // 通道塊在迷宮中的 座標位置
		int direction; // 從該通道塊走向下一個通道塊的 方向
	}

	/**
	 * 存放經過路徑的棧
	 */
	SqStack<StackElem> stack = new SqStack<StackElem>();
	private SqStack<StackElem> getStack() {
		return stack;
	}
	
	/**
	 * 存放走過每個點的是否通過的圖譜
	 */
	int[][] footPrint = new int[10][10];
	private int[][] getPrintFoot() {
		return footPrint;
	}
	
	/**
	 * 原來的迷宮的圖
	 */ 
	static int[][] maze = { 
			{ 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 }, 
			};

	/**
	 * 
	 * @param pos
	 *            位置座標物件
	 * @return 是否可以通過
	 */
	boolean Pass(Position pos) {
		// if(maze[pos.row][pos.col])
			
		/*
		 * maze中的1表示不可通過 footPrint中的1表示可以走 (1為基礎值,如果通過則--,如果最後pop則+=2) 0 1 2
		 * 通過未返回 可通過 通過但是倒回
		 */
		if (maze[pos.row][pos.col] != 1 && footPrint[pos.row][pos.col] == 1)
			return true;
		return false;
	}
	
	/*
	0-------------y col(i)列
	|
	|
	|
	|
	x
	row(j)行
	*/
	Position nextPos(Position curpos, int direction) {
		/*
		 * 這裡應該把向南和向向東分開到四個方向最開始的位置
		 * 因為只有向東和向南才是有效前進
		 * 這樣可以達到優化
		 * 假如:
		 * 		east = 1;
		 * 		south = 2;
		 * 		west = 3; 
		 * 		north = 4;
		 * 		我當前位置的後一個位置不能通過
		 */
		final int east = 1;
		final int south = 2;
		final int west = 3;
		final int north = 4;
		/*       4        
		 *   3       1
		 *       2
		 */
		//  搞清楚向南和向東的關係
		Position pos = new Position();
		pos.col = curpos.col;
		pos.row = curpos.row;
		if (direction == east)
			pos.col++;
		if (direction == south)
			pos.row++;
		if (direction == west)
			pos.col--;
		if (direction == north)
			pos.row--;	
		return pos;
	}

	boolean mazePath(Position start, Position end) {
		Position curpos = start;
		int curstep = 1;
		SqStack<StackElem> stack = new SqStack<StackElem>();
		// int direction = 1;
		StackElem e;
		for (int i = 0; i < 10; i++)
			for (int j = 0; j < 10; j++)
				footPrint[i][j] = 1;
		do {
			// 當前的位置可以通過
			// 沒有走過的位置
			if (Pass(curpos)) {
				footPrint[curpos.row][curpos.col] = 0; // 留下足跡
				e = new StackElem();
				e.ord = curstep;
				e.seat = curpos;
				e.direction = 1;
				System.out.println("第" + e.ord + "步:" + e.seat.row + "行, " + e.seat.col+"列");
				stack.push(e); // 將該點壓入棧中
				if (curpos.row == end.row && curpos.col == end.col) {
					this.stack = stack;
					return true; // 若該點為終點,退出
				}

				curpos = nextPos(curpos, 1);
				/*
				 * 預設的尋找方向是向東的
				 */
				curstep++; // 探索下一步
			}else {
				if (!stack.empty()) {  
					e = stack.pop();
					// 若沒有這個點,進行回溯
					while (4 == e.direction && !stack.empty()) {
						footPrint[e.seat.row][e.seat.col] = 2;
						// 留下不可通過的標記
						e = stack.pop(); // 退回一步
					}
					// 變換方向
					if (e.direction < 4) {
						e.direction++;
						stack.push(e);
						curpos = nextPos(e.seat, e.direction);
						// 更新下一個點的資訊
					}
				}
			}
		} while (!stack.empty());
		return false;
	}
	
	
	public static void main(String[] args) {
		StackSolveMaze ma = new StackSolveMaze();

		StackSolveMaze.Position start = ma.new Position();
		StackSolveMaze.Position end = ma.new Position();
		start.row = 1;
		start.col = 1;
		end.row = 8;
		end.col = 8;
		if (ma.mazePath(start, end)) {
			System.out.println("迷宮可以通過");
		} else {
			System.out.println("迷宮不可通過");
		}
		System.out.println("檢視路徑的情況:(0表示走過,2表示走過但是不可取):");
		int[][] foot = ma.getPrintFoot();
		for (int i = 0; i < 10; i++) {
			for (int j = 0; j < 10; j++) {
				System.out.print(foot[i][j] + " ");
			}
			System.out.println();
		}

		System.out.println("迷宮圖為:");
		for (int row = 0; row < 10; row++) {
			for (int loc = 0; loc < 10; loc++) {
				System.out.print(maze[row][loc] + " ");
			}
			System.out.println();
		}
		
		
		SqStack<StackElem> stack = ma.getStack();
		while (!stack.empty()) {
			StackElem e = (StackElem)stack.pop();
			System.out.println("第" + e.ord + "步:" + e.seat.row + "行, " + e.seat.col+"列");
		}

	}
}

package stack.sq;

import java.util.Arrays;

/**
 * 基於陣列實現的順序棧
 * 
 * top 永遠指向棧頂元素之上的位置
 * top初始值為0    FILO
 * 
 * @author 半步瘋子
 * @param <E>
 */
public class SqStack<E> {
    private Object[] data = null;
    private int stackSize = 0; // 棧容量
    private int addSize = 10; // 每次增加的基數  
    private int top = 0; // 棧頂指標(初始化為0,避免對後面造成影響)
    
    
    //--------------------------
    /**
     *	初始化棧操作
     *
     *	complete
     */
    public SqStack(){
        this(10); // 預設棧大小為10
    }
    public SqStack(int initialSize) throws RuntimeException{
        if(initialSize > 0){
            this.stackSize = initialSize;
            data = new Object[initialSize];
            top = 0;
        }else{ 
            throw new RuntimeException("初始化大小不合理:" + initialSize);
        }
    }
    //--------------------------
    /**
     * 獲取SqStack的元素個數
     * @return 返回表長
     */
    public int stackLength() {
    	return top;
    }
    
    /**
     * 返回分配的儲存長度
     * @return 返回表長
     */
    public int getCapacity() {
    	return stackSize;
    }
    /**
     * 當為空的時候,top為0
     * @return 空時為true  不空的時候為false
     * 
     * complete
     */
    public boolean empty(){
    	return top == 0;
        // return top == 0 ? true : false;
    }
    
    /**
     * 進棧的操作
     * @param e
     * 
     * complete
     */
    public void push(E e){
        if(top == stackSize)   myReallocated();  
            // throw new RuntimeException("棧已滿,無法將元素入棧!");
    	 data[top++]=e; 
      
    }
    
    /**
     * 檢視棧頂元素但不移除 
     * @return
     * 
     * complete
     */
    @SuppressWarnings("unchecked")
	public E peek() throws RuntimeException{
        if(0 == top){
            throw new RuntimeException("棧為空!");
        }else{
            return (E)data[top-1];
        }
    }
    
    /**
     * 彈出棧頂元素
     * @return
     * 
     * complete
     */
    @SuppressWarnings("unchecked")
	public E pop() throws RuntimeException{
        if(0 == top){
            throw new RuntimeException("棧為空!");
        }else{
        	E value = (E)data[top-1];
        	data[--top] = null;
            return value;
        }
    }
    
    /**
     * complete
     */
    private void myReallocated(){
    	/*
		Object[] temp = new Object[stackSize+addSize];
		stackSize = stackSize+addSize;
		System.arraycopy(data, 0, temp, 0, data.length);
		data = temp;
		*/
		if(top == stackSize){
			stackSize += addSize; //將棧容量加10  或增加到10
            data = Arrays.copyOf(data, stackSize);  //將原陣列進行拷貝
        }
		
	}
    
    /**
     * complete
     */
    @SuppressWarnings("unchecked")
	public void stackPrint() {
    	for(int i=0; i<top; i++) {
    		System.out.println((E)data);
    	}
    }
 
}