//定義一個 ArrayStack 表示棧 class ArrayStack { private int maxSize; // 棧的大小 private int[] stack; // 數組,數組模擬棧,數據就放在該數組 private int top = -1;// top表示棧頂,初始化爲-1 //構造器 public ArrayStack(int maxSize) { this.maxSize = maxSize; stack = new int[this.maxSize]; } //棧滿 public boolean isFull() { return top == maxSize - 1; } //棧空 public boolean isEmpty() { return top == -1; } //入棧 public void push(int value) { //先判斷棧是否滿 if(isFull()) { System.out.println("棧滿"); return; } top++; stack[top] = value; } //出棧 //將棧頂的數據返回 public int pop() { //先判斷棧是否空 if(isEmpty()) { //拋出異常 throw new RuntimeException("棧空,沒有數據~"); } int value = stack[top]; top--; return value; } //[遍歷棧], 遍歷時,須要從棧頂開始顯示數據 public void list() { if(isEmpty()) { System.out.println("棧空,沒有數據~~"); return; } //須要從棧頂開始顯示數據 for(int i = top; i >= 0 ; i--) { System.out.printf("stack[%d]=%d\n", i, stack[i]); } }
測試:java
public static void main(String[] args) { //先建立一個arraystack對象表示棧 ArrayStack stack =new ArrayStack(4); String key= ""; boolean loop = true; Scanner scanner =new Scanner(System.in); while (loop){ System.out.println("show: 表示顯示棧"); System.out.println("exit: 退出程序"); System.out.println("push: 表示添加數據到棧(入棧)"); System.out.println("pop: 表示從棧取出數據(出棧)"); System.out.println("請輸入你的選擇"); key = scanner.next(); switch (key) { case "show": stack.list(); break; case "push": System.out.println("請輸入一個數"); int value = scanner.nextInt(); stack.push(value); break; case "pop": try { int res = stack.pop(); System.out.printf("出棧的數據是 %d\n", res); } catch (Exception e) { // TODO: handle exception System.out.println(e.getMessage()); } break; case "exit": scanner.close(); loop = false; break; default: break; } } System.out.println("程序退出了!"); }
簡單的說: 遞歸就是方法自己調用本身,每次調用時傳入不一樣的變量.遞歸有助於編程者解決複雜的問題,同時可讓代碼變得簡潔。程序員
遞歸調用機制算法
說明: 1)小球獲得的路徑,和程序員設置的找路策略有關即:找路的上下左右的順序相關編程
2)再獲得小球路徑時,能夠先使用(下右上左),再改爲(上右下左),看看路徑是不是有變化數組
/** * @author Sun.Mr * @create 2019-09-17 22:21 */ public class Migong { public static void main(String[] args) { //先建立一個二維數組,模擬迷宮 //地圖 int[][] map = new int[8][7]; //使用1表示牆 //上下左右皆置位1 for (int i = 0; i < 7; i++) { map[0][i] = 1; map[7][i] = 1; } for (int i = 0; i < 8; i++) { map[i][0] = 1; map[i][6] = 1; } //設置擋板 map[3][1] = 1; map[3][2] = 1; //輸出地圖 System.out.println("地圖的狀況"); for (int i = 0; i < 7; i++) { for (int j = 0; j < 7; j++) { System.out.print(map[i][j] + " "); } System.out.println(); } //使用遞歸回溯給小球找路 setWay(map, 1, 1); //輸出新的地圖, 小球走過,並標識過的遞歸 System.out.println("小球走過,並標識過的 地圖的狀況"); for (int i = 0; i < 8; i++) { for (int j = 0; j < 7; j++) { System.out.print(map[i][j] + " "); } System.out.println(); } } //使用遞歸回溯給小球找路 //(1,1)----->(6,5) //4. 約定: 當map[i][j] 爲 0 表示該點沒有走過 當爲 1 表示牆 ; 2 表示通路能夠走 ; 3 表示該點已經走過,可是走不通 //5. 在走迷宮時,須要肯定一個策略(方法) 下->右->上->左 , 若是該點走不通,再回溯 /** * * @param map 表示地圖 * @param i 從哪一個位置開始找 * @param j * @return 若是找到通路,就返回true,不然就返回false */ public static boolean setWay(int[][] map, int i, int j) { if(map[6][5] == 2) { // 通路已經找到ok return true; } else { if(map[i][j] == 0) { //若是當前這個點尚未走過 //按照策略 下->右->上->左 走 map[i][j] = 2; // 假定該點是能夠走通. if(setWay(map, i+1, j)) {//向下走 return true; } else if (setWay(map, i, j+1)) { //向右走 return true; } else if (setWay(map, i-1, j)) { //向上 return true; } else if (setWay(map, i, j-1)){ // 向左走 return true; } else { //說明該點是走不通,是死路 map[i][j] = 3; return false; } } else { // 若是map[i][j] != 0 , 多是 1, 2, 3 return false; } } } }
八皇后問題,是一個古老而著名的問題,是回溯算法的典型案例。該問題是國際西洋棋棋手馬克斯·貝瑟爾於1848年提出:在8×8格的國際象棋上擺放八個皇后,使其不能互相攻擊,即:任意兩個皇后都不能處於同一行、同一列或同一斜線上,問有多少種擺法。oop
八皇後問題算法思路分析測試
說明:理論上應該建立一個二維數組來表示棋盤,可是實際上能夠經過算法,用一個一維數組便可解決問題. arr[8] = {0 , 4, 7, 5, 2, 6, 1, 3} //對應arr 下標 表示第幾行,即第幾個皇后,arr[i] = val , val 表示第i+1個皇后,放在第i+1行的第val+1列this
代碼實現:google
package com.xtkj; /** * @author Sun.Mr * @create 2019-09-18 10:54 */ public class Queue8 { //定義一個max表示共有多少個皇后 int max = 8; //定義數組array, 保存皇后放置位置的結果,好比 arr = {0 , 4, 7, 5, 2, 6, 1, 3} int[] array = new int[max]; static int count = 0; public static void main(String[] args) { //測試一把 , 8皇后是否正確 Queue8 queue8 = new Queue8(); queue8.check(0); System.out.printf("一共有%d解法", count); } //編寫一個方法,放置第n個皇后 public void check(int n){ if (n == max) { print(); return; } //依次放入皇后,並判斷是否衝突 for(int i = 0; i < max; i++) { //先把當前這個皇后 n , 放到該行的第1列 array[n] = i; //判斷當放置第n個皇后到i列時,是否衝突 if(judge(n)) { // 不衝突 //接着放n+1個皇后,即開始遞歸 check(n+1); // } //若是衝突,就繼續執行 array[n] = i; 即將第n個皇后,放置在本行得 後移的一個位置 } } /** * 查看當咱們放置第n個皇后, 就去檢測該皇后是否和前面已經擺放的皇后衝突 * @param n * @return */ private boolean judge(int n) { // 說明 //1. array[i] == array[n] 表示判斷 第n個皇后是否和前面的n-1個皇后在同一列 //2. Math.abs(n-i) == Math.abs(array[n] - array[i]) 表示判斷第n個皇后是否和第i皇后是否在同一斜線 // n = 1 放置第 2列 1 n = 1 array[1] = 1 // Math.abs(1-0) == 1 Math.abs(array[n] - array[i]) = Math.abs(1-0) = 1 //3. 判斷是否在同一行, 沒有必要,n 每次都在遞增 for (int i = 0; i < n; i++) { // 說明 //1. array[i] == array[n] 表示判斷 第n個皇后是否和前面的n-1個皇后在同一列 //2. Math.abs(n-i) == Math.abs(array[n] - array[i]) 表示判斷第n個皇后是否和第i皇后是否在同一斜線 // n = 1 放置第 2列 1 n = 1 array[1] = 1 // Math.abs(1-0) == 1 Math.abs(array[n] - array[i]) = Math.abs(1-0) = 1 //3. 判斷是否在同一行, 沒有必要,n 每次都在遞增 if (array[i] == array[n] || Math.abs(n - i) == Math.abs(array[n] - array[i])) { return false; } } return true; } private void print() { count++; for (int i = 0; i < array.length; i++) { System.out.print(array[i] + " "); } System.out.println(); } }