稀疏数组和队列
1. 稀疏數組sparsearray
1.1 運用場景
- 編寫的五子棋程序中, 有存盤退出和續上盤的功能。
- 分析問題:
因為該二維數組的很多值是默認值 0, 因此記錄了很多沒有意義的數據,這個時候我們就可以運用稀疏數組。
?
1.2 解決方案
- 當一個數組中大部分元素為0 , 或者為同一個值的數組時, 可以使用稀疏數組來保存該數組。
- 稀疏數組的處理方法:
1.3 應用實例
- 使用稀疏數組, 來保留類似前面的二維數組(棋盤、 地圖等等)
- 把稀疏數組存盤, 并且可以從新恢復原來的二維數組數
- 整體思路分析:
1.4 代碼實現
package com.gtjt.xxjss.parsearry;public class SparseArray {/*** 二維數組轉換成稀疏數組** @param dyadicArry* @return*/public static int[][] dyadicArrayConvertIntoSparseArray(int[][] dyadicArry) {//1.遍歷原始的二維數組,得到有效數據的個數sumint sum = 0;for (int i = 0;i < dyadicArry.length;i++) {for (int j = 0;j < dyadicArry[i].length;j++) {if (dyadicArry[i][j] != 0) {sum++;}}}//2.根據sum就可以創建稀疏數組sparseArray int[sum+1][3]int[][] sparseArray = new int[sum+1][3];sparseArray[0][0] = dyadicArry.length;sparseArray[0][1] = sparseArray[0][0];sparseArray[0][2] = sum;//3.將二維數組的有效數據存入稀疏數組int k = 1;for (int i = 0;i < dyadicArry.length;i++) {for (int j = 0;j < dyadicArry[i].length;j++) {if (dyadicArry[i][j] != 0) {sparseArray[k][0] = i;sparseArray[k][1] = j;sparseArray[k][2] = dyadicArry[i][j];k++;}}}return sparseArray;}/*** 稀疏數組轉換成二維數組** @param sparseArray* @return*/public static int[][] sparseArrayConvertIntoDyadicArray(int[][] sparseArray) {//1.先讀取稀疏數組的第一行,根據第一行的數據,創建原始的二維數組int[][] dyadicArray = new int[sparseArray[0][0]][sparseArray[0][1]];//2.在讀取稀疏數組后幾行的數據,并賦值給原始的二維數組即可for (int i = 1;i <= sparseArray[0][2];i++) {dyadicArray[sparseArray[i][0]][sparseArray[i][1]] = sparseArray[i][2];}return dyadicArray;}public static void main(String[] args) {int[][] dyadicArry ={{0,0,0,0,0,0,0,0,0,0,0},{0,0,1,0,0,0,0,0,0,0,0},{0,0,0,2,0,0,0,0,0,0,0},{0,0,0,0,0,0,0,0,0,0,0},{0,0,0,0,0,0,0,0,0,0,0},{0,0,0,0,0,0,0,0,0,0,0},{0,0,0,0,0,0,0,0,0,0,0},{0,0,0,0,0,0,0,0,0,0,0},{0,0,0,0,0,0,0,0,0,0,0},{0,0,0,0,0,0,0,0,0,0,0},{0,0,0,0,0,0,0,0,0,0,0}};System.out.println("原始的二維數組:");for (int[] d : dyadicArry) {for (int i = 0;i < d.length;i++) {System.out.printf("%d\t", d[i]);}System.out.println();}int[][] sparseArray = dyadicArrayConvertIntoSparseArray(dyadicArry);System.out.println("二維數組轉換后的稀疏數組:");for (int[] s : sparseArray) {for (int i = 0;i < s.length;i++) {System.out.printf("%d\t", s[i]);}System.out.println();}int [][] dyadicArry2 = sparseArrayConvertIntoDyadicArray(sparseArray);System.out.println("稀疏數組轉換后的二維數組:");for (int[] d : dyadicArry2) {for (int i = 0;i < d.length;i++) {System.out.printf("%d\t", d[i]);}System.out.println();}}}1.5 程序運行結果
原始的二維數組: 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 二維數組轉換后的稀疏數組: 11 11 2 1 2 1 2 3 2 稀疏數組轉換后的二維數組: 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 01.4 課后練習
- 在前面的基礎上, 將稀疏數組保存到磁盤上, 比如 map.data
- 恢復原來的數組時, 讀取 map.data 進行恢復
?
2. 隊列
2.1 隊列的一個使用場景
銀行排隊的案例:
2.2 隊列介紹
2.3 數組模擬隊列思路
- 隊列本身是有序列表, 若使用數組的結構來存儲隊列的數據, 則隊列數組的聲明如下圖, 其中 maxSize 是該隊列的最大容量。
- 因為隊列的輸出、 輸入是分別從前后端來處理, 因此需要兩個變量 front 及 rear 分別記錄隊列前后端的下標,
- front 會隨著數據輸出而改變, 而 rear 則是隨著數據輸入而改變, 如圖所示:
- 當我們將數據存入隊列時稱為” addQueue” , addQueue 的處理需要有兩個步驟: 思路分析
2.4 代碼實現
package com.gtjt.xxjss.queue;import java.util.Scanner;public class ArrayQueueDemo {public static void main(String[] args) {ArrayQueue queue = new ArrayQueue(3);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;}}System.out.println("程序退出~~");} }class ArrayQueue {private int maxSize;//隊列最大長度private int front;//指向隊列頭部前一個位置private int rear;//指向隊列尾部,包含尾部private int[] array;//構造一個長度為size的隊列public ArrayQueue(int size) {maxSize = size;front = -1;//隊列頭部,指向的是隊列頭的前一個位置rear = -1;//隊列尾部,指向隊列尾的數據(隊列的最后一個數據)array = new int[size];}//判斷隊列是否空public boolean isEmpty() {return front == rear;}//判斷隊列是否滿public boolean isFull() {return rear == maxSize - 1;}//往隊列存數public void addQueue(int n) {if (isFull()) {System.out.println("隊列滿,不能存數!");return;}rear++;array[rear] = n;}//從隊列中取數public int getQueue() {if (isEmpty()) {throw new RuntimeException("隊列空,不能取數!");}front++;return array[front];}//顯示隊列public void showQueue() {if (isEmpty()) {System.out.println("隊列為空,沒有數據!");return;}for (int i = (front + 1);i < rear + 1;i++) {System.out.printf("array[%d]:%d\n",i, array[i]);}}//取出隊列頭數據public int headQueue() {if (isEmpty()) {throw new RuntimeException("隊列空,不能取數!");}return array[front + 1];} }2.5 程序運行結果
s(show):顯示隊列 e(exit):退出程序 a(add):添加數據到隊列 g(get):從隊列中取出數據 h(head):查看隊列頭部數據 a 請輸入一個整數: 1 s(show):顯示隊列 e(exit):退出程序 a(add):添加數據到隊列 g(get):從隊列中取出數據 h(head):查看隊列頭部數據 a 請輸入一個整數: 2 s(show):顯示隊列 e(exit):退出程序 a(add):添加數據到隊列 g(get):從隊列中取出數據 h(head):查看隊列頭部數據 a 請輸入一個整數: 3 s(show):顯示隊列 e(exit):退出程序 a(add):添加數據到隊列 g(get):從隊列中取出數據 h(head):查看隊列頭部數據 a 請輸入一個整數: 4 隊列滿,不能存數! s(show):顯示隊列 e(exit):退出程序 a(add):添加數據到隊列 g(get):從隊列中取出數據 h(head):查看隊列頭部數據 h 隊列頭部的數據是:1 s(show):顯示隊列 e(exit):退出程序 a(add):添加數據到隊列 g(get):從隊列中取出數據 h(head):查看隊列頭部數據 g 取出的數據是:1 s(show):顯示隊列 e(exit):退出程序 a(add):添加數據到隊列 g(get):從隊列中取出數據 h(head):查看隊列頭部數據 s array[1]:2 array[2]:3 s(show):顯示隊列 e(exit):退出程序 a(add):添加數據到隊列 g(get):從隊列中取出數據 h(head):查看隊列頭部數據 g 取出的數據是:2 s(show):顯示隊列 e(exit):退出程序 a(add):添加數據到隊列 g(get):從隊列中取出數據 h(head):查看隊列頭部數據 g 取出的數據是:3 s(show):顯示隊列 e(exit):退出程序 a(add):添加數據到隊列 g(get):從隊列中取出數據 h(head):查看隊列頭部數據 g 隊列空,不能取數! s(show):顯示隊列 e(exit):退出程序 a(add):添加數據到隊列 g(get):從隊列中取出數據 h(head):查看隊列頭部數據 s 隊列為空,沒有數據! s(show):顯示隊列 e(exit):退出程序 a(add):添加數據到隊列 g(get):從隊列中取出數據 h(head):查看隊列頭部數據 a 請輸入一個整數: 4 隊列滿,不能存數! s(show):顯示隊列 e(exit):退出程序 a(add):添加數據到隊列 g(get):從隊列中取出數據 h(head):查看隊列頭部數據2.6?問題分析并優化
- 目前數組使用一次就不能用, 沒有達到復用的效果
- 將這個數組使用算法, 改進成一個環形的隊列 取模: %
?
3. 數組模擬環形隊列
? 3.1 對前面的數組模擬隊列進行優化, 充分利用數組,可將數組看是一個環形的。 (通過取模的方式來實現)
- 分析說明:
3.2 代碼實現
package com.gtjt.xxjss.queue;import java.util.Scanner;public class CircleArrayQueueDemo {public static void main(String[] args) {CircleArrayQueue queue = new CircleArrayQueue(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;}}System.out.println("程序退出~~");} }class CircleArrayQueue {private int maxSize;//隊列最大長度private int front;//指向隊列頭部,隊列第一個元素的位置private int rear;//指向隊列尾部,隊列最后一個元素的下一個位置(因為預留出一個空間,區分隊列滿和隊列空的情況)private int[] array;//構造器public CircleArrayQueue(int size) {maxSize = size;front = 0;rear = 0;array = new int[size];}//判斷隊列是否空public boolean isEmpty() {return front == rear;}//判斷隊列是否滿public boolean isFull() {return (rear + 1) % maxSize == front;}//往隊列存數public void addQueue(int n) {if (isFull()) {System.out.println("隊列滿,不能存數!");return;}array[rear] = n;//直接將數據寫入rear = (rear + 1) % maxSize;//將rear后移, 這里要考慮取模}//從隊列中取數public int getQueue() {if (isEmpty()) {throw new RuntimeException("隊列空,不能取數!");}// 因為front是指向隊列的第一個元素// 1. 先把 front 對應的值保留到一個臨時變量// 2. 將 front 后移, 要考慮取模// 3. 將臨時保存的變量返回int val = array[front];front = (front + 1) % maxSize;return val;}//顯示隊列的所有數據public void showQueue() {if (isEmpty()) {System.out.println("隊列為空,沒有數據!");return;}// 思路:從front開始遍歷,遍歷多少個元素// 關鍵點:環形隊列,front的值會在0到maxSize-1之間不斷循環for (int i = front;i < front + size();i++) {System.out.printf("array[%d]:%d\n",i % maxSize, array[i % maxSize]);}}//計算隊列的有效值個數public int size() {return ((rear - front + maxSize) % maxSize);}//取出隊列頭數據public int headQueue() {if (isEmpty()) {throw new RuntimeException("隊列空,不能取數!");}return array[front];} }3.3 程序運行結果
s(show):顯示隊列 e(exit):退出程序 a(add):添加數據到隊列 g(get):從隊列中取出數據 h(head):查看隊列頭部數據 a 請輸入一個整數: 1 s(show):顯示隊列 e(exit):退出程序 a(add):添加數據到隊列 g(get):從隊列中取出數據 h(head):查看隊列頭部數據 a 請輸入一個整數: 2 s(show):顯示隊列 e(exit):退出程序 a(add):添加數據到隊列 g(get):從隊列中取出數據 h(head):查看隊列頭部數據 a 請輸入一個整數: 3 s(show):顯示隊列 e(exit):退出程序 a(add):添加數據到隊列 g(get):從隊列中取出數據 h(head):查看隊列頭部數據 a 請輸入一個整數: 4 隊列滿,不能存數! s(show):顯示隊列 e(exit):退出程序 a(add):添加數據到隊列 g(get):從隊列中取出數據 h(head):查看隊列頭部數據 s array[0]:1 array[1]:2 array[2]:3 s(show):顯示隊列 e(exit):退出程序 a(add):添加數據到隊列 g(get):從隊列中取出數據 h(head):查看隊列頭部數據 g 取出的數據是:1 s(show):顯示隊列 e(exit):退出程序 a(add):添加數據到隊列 g(get):從隊列中取出數據 h(head):查看隊列頭部數據 h 隊列頭部的數據是:2 s(show):顯示隊列 e(exit):退出程序 a(add):添加數據到隊列 g(get):從隊列中取出數據 h(head):查看隊列頭部數據 g 取出的數據是:2 s(show):顯示隊列 e(exit):退出程序 a(add):添加數據到隊列 g(get):從隊列中取出數據 h(head):查看隊列頭部數據 s array[2]:3 s(show):顯示隊列 e(exit):退出程序 a(add):添加數據到隊列 g(get):從隊列中取出數據 h(head):查看隊列頭部數據 g 取出的數據是:3 s(show):顯示隊列 e(exit):退出程序 a(add):添加數據到隊列 g(get):從隊列中取出數據 h(head):查看隊列頭部數據 g 隊列空,不能取數! s(show):顯示隊列 e(exit):退出程序 a(add):添加數據到隊列 g(get):從隊列中取出數據 h(head):查看隊列頭部數據 a 請輸入一個整數: 4 s(show):顯示隊列 e(exit):退出程序 a(add):添加數據到隊列 g(get):從隊列中取出數據 h(head):查看隊列頭部數據 a 請輸入一個整數: 5 s(show):顯示隊列 e(exit):退出程序 a(add):添加數據到隊列 g(get):從隊列中取出數據 h(head):查看隊列頭部數據 s array[3]:4 array[0]:5 s(show):顯示隊列 e(exit):退出程序 a(add):添加數據到隊列 g(get):從隊列中取出數據 h(head):查看隊列頭部數據 a 請輸入一個整數: 6 s(show):顯示隊列 e(exit):退出程序 a(add):添加數據到隊列 g(get):從隊列中取出數據 h(head):查看隊列頭部數據 a 請輸入一個整數: 7 隊列滿,不能存數! s(show):顯示隊列 e(exit):退出程序 a(add):添加數據到隊列 g(get):從隊列中取出數據 h(head):查看隊列頭部數據 s array[3]:4 array[0]:5 array[1]:6 s(show):顯示隊列 e(exit):退出程序 a(add):添加數據到隊列 g(get):從隊列中取出數據 h(head):查看隊列頭部數據 g 取出的數據是:4 s(show):顯示隊列 e(exit):退出程序 a(add):添加數據到隊列 g(get):從隊列中取出數據 h(head):查看隊列頭部數據 h 隊列頭部的數據是:5 s(show):顯示隊列 e(exit):退出程序 a(add):添加數據到隊列 g(get):從隊列中取出數據 h(head):查看隊列頭部數據 a 請輸入一個整數: 7 s(show):顯示隊列 e(exit):退出程序 a(add):添加數據到隊列 g(get):從隊列中取出數據 h(head):查看隊列頭部數據 s array[0]:5 array[1]:6 array[2]:7 s(show):顯示隊列 e(exit):退出程序 a(add):添加數據到隊列 g(get):從隊列中取出數據 h(head):查看隊列頭部數據 a 請輸入一個整數: 8 隊列滿,不能存數! s(show):顯示隊列 e(exit):退出程序 a(add):添加數據到隊列 g(get):從隊列中取出數據 h(head):查看隊列頭部數據 s array[0]:5 array[1]:6 array[2]:7 s(show):顯示隊列 e(exit):退出程序 a(add):添加數據到隊列 g(get):從隊列中取出數據 h(head):查看隊列頭部數據?
?
?
?
總結