java自定義棧實現簡單迷宮
阿新 • • 發佈:2019-02-10
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); } } }