所謂稀疏數組就是當數組中大部分的內容值都未被使用(或都爲零),在數組中僅有少部分的空間使用。所以形成內存空間的浪費,爲了節省內存空間,而且不影響數組中原有的內容值,咱們可使用稀疏數組去壓縮數據。OK,若是你不明白,那咱們來看一個例子。小程序
在一個五子棋中,有存盤和續上盤的功能數組
分析問題:由於該二維數組的不少默認值是 0,所以記錄了不少沒有意義的數據 > 稀疏數組數據結構
思路oop
記錄數組一共有幾行幾列,有多少個不一樣的值測試
把具備不一樣值的元素的行列及值記錄在一個小規模的數組中,從而縮小程序的範圍優化
應用實例this
public class SparseArray { public static void main(String[] args) { //建立一個二維數組 //0:表示沒有棋子 1表示黑子 2表示藍子 int chessArr[][] = new int[11][10]; chessArr[1][2] = 1; chessArr[2][3] = 2; for(int[] row:chessArr){ for(int data:row){ System.out.printf("%d\t",data); } System.out.println(); } int[][] array = getSparseArray(chessArr); System.out.println("-------"); for(int i = 0 ; i< array.length;i++){ System.out.printf("%d\t%d\t%d\t\n",array[i][0],array[i][1],array[i][2]); } System.out.println("--------"); int[][] startArr = recovery(array); for(int[] row:startArr){ for(int data:row){ System.out.printf("%d\t",data); } System.out.println(); } } /** * 將普通數組轉換爲稀疏數組 * @param chessArr * @return */ public static int[][] getSparseArray(int[][] chessArr){ if(!checkIsRight(chessArr)){ return null; } //1.拿到數組後 首先獲取元素的個數,而後才能創建稀疏數組 int sum = 0; for(int[] arr:chessArr){ for(int i:arr){ if(i != 0){ sum++; } } } //2.創建稀疏數組 int[][] sparseArr = new int[sum+1][3]; sparseArr[0][0] = chessArr.length; //行 sparseArr[0][1] = chessArr[0].length;//列 sparseArr[0][2] = sum; //元素個數 //3.數組存放 int count = 0; for(int i = 0; i <chessArr.length; i++ ){ for(int j = 0; j <chessArr[i].length;j++ ){ if(chessArr[i][j] != 0){ sparseArr[++count][0] = i;//行 sparseArr[count][1] = j;//列 sparseArr[count][2] = chessArr[i][j]; } } } return sparseArr; } /** * 將稀疏數組轉回普通數組 * @param sparseArr * @return */ public static int[][] recovery(int[][] sparseArr){ if(!checkIsRight(sparseArr)){ return null; } //獲取原數組的 行數和列數 並建立原數組 int arr[][] = new int[sparseArr[0][0]][sparseArr[0][1]]; for(int i = 1; i < sparseArr.length;i++){ arr[sparseArr[i][0]][sparseArr[i][1]] = sparseArr[i][2]; } return arr; } public static boolean checkIsRight(int[][] arr){ if(arr == null || arr.length <= 1 ){ return false; } return true; } }
addQueue
,addQueue
的處理有兩個步驟:思路分析(1) 將尾指針日後移:rear+1,當front == rear [空]spa
(2) 若尾指針rear小於隊列的最大下標 maxSize - 1,則數據輸入rear 所指的數組元素中,不然沒法存入數據。指針
rear == maxSize - 1
代碼實現
public class ArrayQueueDemo { public static void main(String[] args) { ArrayQueue queue = new ArrayQueue(10); queue.addQueue(1); queue.addQueue(2); queue.addQueue(3); queue.addQueue(4); queue.getQueue(); queue.showQueue(); } } //使用數組模擬隊列-編寫一個ArrayQueue類 class ArrayQueue{ private int maxSize; //表示數組的最大容量 private int front;//隊列頭 private int rear;//隊列尾 private int[] arr; //該數組用於存放數據,模擬隊列 public ArrayQueue(int maxSize){ this.maxSize = maxSize; arr = new int[maxSize]; this.front = -1; this.rear = -1; } //判斷隊列是否已滿 public boolean isFull(){ return rear == maxSize - 1; } //判斷隊列是否爲空 public boolean isEmpty(){ return front == rear; } //添加數據到隊列 public void addQueue(int n){ //判斷隊列是否滿 if(isFull()){ System.out.println("隊列已滿"); return; } arr[++rear] = n; } //獲取隊列的數據,出隊列 public int getQueue(){ if(isEmpty()){ throw new RuntimeException("隊列已空"); } return arr[++front]; } //顯示隊列全部數據 public void showQueue(){ if(isEmpty()){ System.out.println("隊列已空"); return; } for(int i = front+1 ;i <= rear;i++){ System.out.printf("arr[%d]=%d\n",i,arr[i]); } } }
以前實現的隊列存在一個明顯的問題,就是數組使用一次就不能再用了,出隊列數據的位置始終空在那,沒有達到一個複用的效果,所以咱們要對這個隊列進行一次優化,將此隊列變成一個環形隊列
思路
front 變量的含義作一個調整:front就指向隊列的第一個元素,也就是 arr[front] 就表明隊列的第一個元素,
front初始值 = 0
rear 的變量含義作一個調整:rear指向最後一個元素的後一個位置,由於但願空出一個空間做爲約定,rear的初始值 = 0
當隊列滿時,條件是 (rear + 1) % maxSize == front 【滿】
當隊列爲空的條件,rear == front 空
當咱們這樣分析,隊列中有效的數據的個數 (rear + maxSize - front) % maxSize
咱們就能夠在原來的隊列上修改獲得 一個環形隊列
代碼實現
public class CircleArrayQueueDemo { public static void main(String[] args) { //測試一把 System.out.println("測試數組模擬環形隊列的案例"); //建立一個環形隊列 說明設置4,其隊列數據最大是3 CircleArray queue = new CircleArray(4); char key = ' ';//接收用戶輸入 Scanner scanner = new Scanner(System.in); boolean loop = true; //輸出一個菜單 while(loop){ System.out.println("s(show):顯示隊列"); System.out.println("e(exit):退出程序"); System.out.println("a(add):添加數據到隊列"); System.out.println("g(get):從隊列取出數據"); System.out.println("h(head):查看隊列頭的數據"); key = scanner.next().charAt(0); switch (key) { case 's': queue.showQueue(); break; case 'a': System.out.println("輸出一個數字"); int value = scanner.nextInt(); queue.addQueue(value); break; case 'g': try { int res = queue.getQueue(); System.out.printf("取出的數據是%d\n",res); } catch (Exception e) { System.out.println(e.getMessage()); } break; case 'h'://查看隊列頭的數據 try { int res = queue.headQueue(); System.out.printf("隊列頭的數據是%d\n",res); } catch (Exception e) { System.out.println(e.getMessage()); } break; case 'e'://退出 scanner.close(); loop = false; break; default: break; } } } } class CircleArray{ private int maxSize; private int front; private int rear; private int[] arr; public CircleArray(int maxSize){ this.maxSize = maxSize; arr = new int[maxSize]; } //判斷隊列是否已滿 public boolean isFull(){ return (rear+1)%maxSize == front; } //判斷隊列是否爲空 public boolean isEmpty(){ return rear == front; } //添加數據到隊列 public void addQueue(int n){ //判斷隊列是否已滿 if(isFull()){ System.out.println("隊列滿,不能加入數據"); return; } //直接將數據加入 arr[rear] = n; //將rear後移,這裏必須考慮取模 rear = (rear+1)%maxSize; } //獲取隊列的數據 public int getQueue(){ //判斷隊列是否爲空 if(isEmpty()){ //經過拋出異常 throw new RuntimeException("隊列爲空,不能取數據"); } int value = arr[front]; front = (front+1)%maxSize; return value; } //顯示隊列的全部數據 public void showQueue(){ //遍歷 if(isEmpty()){ System.out.println("隊列爲空,沒有數據"); return; } for(int i = front; i < front + size() ; i++){ System.out.printf("arr[%d]=%d\n",i%maxSize,arr[i%maxSize]); } } //求出當前隊列有效數據的個數 public int size(){ //加上maxSize 防止模出負數 由於這是一個環形隊列 return (rear + maxSize - front)%maxSize; } //顯示隊列的頭數據 public int headQueue(){ //判斷 if(isEmpty()){ throw new RuntimeException("隊列是空的,~沒有數據"); } return arr[front]; } }