生活随笔
收集整理的這篇文章主要介紹了
数据结构之稀疏数组队列
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
文章目錄
- 1、稀疏數組
- 1.1、實際需求
- 1.2、稀疏數組應用
- 1.3、應用實例
- 1.4、課后練習
- 2、隊列
- 2.1、隊列使用場景
- 2.2、隊列介紹
- 2.3、數組模擬隊列
- 2.4、數組模型環形隊列
- 2.4.1、提出問題
- 2.4.2、思路分析
- 2.4.3、代碼實現
1、稀疏數組
1.1、實際需求
- 編寫的五子棋程序中,有存盤退出和續上盤的功能
- 因為該二維數組的很多值是默認值 0 ,因此 記錄了很多沒有意義的數據,我們將其轉為 稀疏數組進行存儲
1.2、稀疏數組應用
1.2.1、稀疏數組處理方法
- 稀疏數組把具有不同值的元素的 行列及值記錄在一個小規模的數組中,從而縮小程序的規模
- 稀疏數組也是二維數組,行數由原數組的數據決定,列數一般為 3 列
- 稀疏數組的 第一行記錄原數組一共有幾行幾列,有多少個不為零的值
- 第一列:原數組的行數
- 第二列:原數組的列數
- 第三列:原數組有多少個不為零的值
- 之后的行記錄原數組中 不為零(x)的值所在的行數、列數以及 x 的值
- 第一列:x 在原數組中的行數
- 第二列:x 在原數組中的列數
- 第三列:x 的值
1.2.2、舉例說明
1.3、應用實例
1.3.1、思路分析
- 使用稀疏數組, 來保留類似前面的二維數組(棋盤、 地圖等等)
- 把稀疏數組存盤, 并且可以從新恢復原來的二維數組數
1.3.2、代碼實現
public class SparseArray {public static void main(String
[] args
) {int chessArr1
[][] = new int[11][11];chessArr1
[1][2] = 1;chessArr1
[2][3] = 2;chessArr1
[4][5] = 2;System
.out
.println("原始的二維數組~~");for (int[] row
: chessArr1
) {for (int data
: row
) {System
.out
.printf("%d\t", data
);}System
.out
.println();}int sum
= 0;for (int i
= 0; i
< chessArr1
.length
; i
++) {for (int j
= 0; j
< chessArr1
[i
].length
; j
++) {if (chessArr1
[i
][j
] != 0) {sum
++;}}}int sparseArr
[][] = new int[sum
+ 1][3];sparseArr
[0][0] = chessArr1
.length
;sparseArr
[0][1] = chessArr1
[0].length
;sparseArr
[0][2] = sum
;int count
= 0;for (int i
= 0; i
< chessArr1
.length
; i
++) {for (int j
= 0; j
< chessArr1
[i
].length
; j
++) {if (chessArr1
[i
][j
] != 0) {count
++;sparseArr
[count
][0] = i
;sparseArr
[count
][1] = j
;sparseArr
[count
][2] = chessArr1
[i
][j
];}}}System
.out
.println();System
.out
.println("得到稀疏數組為~~~~");for (int i
= 0; i
< sparseArr
.length
; i
++) {System
.out
.printf("%d\t%d\t%d\n", sparseArr
[i
][0], sparseArr
[i
][1], sparseArr
[i
][2]);}System
.out
.println();int chessArr2
[][] = new int[sparseArr
[0][0]][sparseArr
[0][1]];for (int i
= 1; i
< sparseArr
.length
; i
++) {chessArr2
[sparseArr
[i
][0]][sparseArr
[i
][1]] = sparseArr
[i
][2];}System
.out
.println();System
.out
.println("恢復后的二維數組");for (int[] row
: chessArr2
) {for (int data
: row
) {System
.out
.printf("%d\t", data
);}System
.out
.println();}}}
原始的二维数组~~
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 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得到稀疏数组为~~~~
11 11 3
1 2 1
2 3 2
4 5 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 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
1.4、課后練習
- 在前面的基礎上, 將稀疏數組保存到磁盤上, 比如 map.data
- 恢復原來的數組時, 讀取 map.data 進行恢復
2、隊列
2.1、隊列使用場景
2.2、隊列介紹
- 隊列是一個有序列表, 可以用數組或是鏈表來實現。
- 遵循 先入先出的原則, 即: 先存入隊列的數據, 要先取出,后存入的要后取出
- 示意圖: (使用數組模擬隊列示意圖)
2.3、數組模擬隊列
2.3.1、思路分析
- maxSize :隊列容量(數組的長度)
- arr :模擬隊列的數組
- front :指向隊列頭部元素的前一個元素,初始值為 -1
- rear :指向隊列尾部元素,初始值為 -1
- 基本操作
- 隊列判空: front == rear
- 隊列判滿: rear == (maxSize - 1) ,即 rear 是否已經指向了數組的最后一個位置
- 隊列元素個數:rear - front
- 隊列入隊:隊列不滿才能入隊,arr[++rear] = value
- 隊列出隊:隊列不空才能出隊,return arr[front++]
2.3.2、代碼實現
class ArrayQueue {private int maxSize
;private int front
;private int rear
;private int[] arr
;public ArrayQueue(int arrMaxSize
) {maxSize
= arrMaxSize
;arr
= new int[maxSize
];front
= -1;rear
= -1;}public boolean isFull() {return rear
== maxSize
- 1;}public boolean isEmpty() {return rear
== front
;}public void addQueue(int n
) {if (isFull()) {System
.out
.println("隊列滿,不能加入數據~");return;}rear
++;arr
[rear
] = n
;}public int getQueue() {if (isEmpty()) {throw new RuntimeException("隊列空,不能取數據");}front
++;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
]);}}public int headQueue() {if (isEmpty()) {throw new RuntimeException("隊列空的,沒有數據~~");}return arr
[front
+ 1];}
}
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): 查看隊列頭的數據");System
.out
.println();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("程序退出~~");}}
s(show): 显示队列
e(exit): 退出程序
a(add): 添加数据到队列
g(get): 从队列取出数据
h(head): 查看队列头的数据s
队列空的,没有数据~~
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): 查看队列头的数据s
arr[0]=1
arr[1]=2
arr[2]=3
s(show): 显示队列
e(exit): 退出程序
a(add): 添加数据到队列
g(get): 从队列取出数据
h(head): 查看队列头的数据a
输出一个数
4
队列满,不能加入数据~
s(show): 显示队列
e(exit): 退出程序
a(add): 添加数据到队列
g(get): 从队列取出数据
h(head): 查看队列头的数据g
取出的数据是1
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): 查看队列头的数据
2.4、數組模型環形隊列
2.4.1、提出問題
- 目前數組 使用一次就不能用, 沒有達到復用的效果,造成 內存空間的浪費
- 將這個數組使用算法, 改進成一個 環形的隊列( 取模: %)
2.4.2、思路分析
- 對前面的隊列進行優化,改造為環形隊列(通過 取模實現)
- maxSize :隊列容量(數組的長度)
- arr :模擬隊列的數組
- front :指向隊列頭部元素,初始值為 0
- rear :指向隊列尾部元素的后一個元素,初始值為 0
- 基本操作
- 隊列判空: front == rear
- 隊列判滿:
- 為何要在 rear 之后,front 之前空出一個元素的空間?因為如果不空出一個元素,隊列判空條件為:front == rear ,隊列判滿的條件也是:front == rear , 有歧義!
- 隊列容量:因為空出了一個元素,所以隊列容量就變成了 (maxSize - 1)
- 當空出一個元素的空間,如何判滿?當還剩一個元素時,隊列就已經滿了,所以判斷條件為 (rear + 1) % maxSize == front
- 隊列元數個數:
- 計算公式: (rear + maxSize - front) % maxSize ,這樣來思考:
- 當 rear 比 front 大時,即 (rear -front) > 0 ,這時還沒有形成環形結構, (rear -front) 即是隊列元素個數
- 當 rear 比 front 小時,即 (rear -front) < 0 ,這時已經形成了環形結構, (rear -front) 表示數組還差多少個元素存滿(負數), (rear + maxSize - front) 即是隊列元素個數
- 綜上: (rear + maxSize - front) % maxSize
- 隊列入隊:
- 首先,隊列不滿才能入隊
- 由于 rear 指向 隊列尾部元素的后一個元素,所以直接設置即可: arr[rear] = value
- 接下來,rear 應該向后移動一個位置: rear = (rear + 1) % maxSize
- 取模是為了 防止數組越界,讓指針從新回到數組第一個元素
- 隊列出隊:
- 首先,隊列不空才能出隊
- 由于 front 直接指向隊列頭部元素,所以直接返回該元素即可:int value = arr[front ]
- 接下來,front 應該向后移動一個位置: front = (front + 1) % maxSize
- 取模是為了 *防止數組越界,讓指針從新回到數組第一個元素
2.4.3、代碼實現
class CircleArray {private int maxSize
;private int front
;private int rear
;private int[] arr
;public CircleArray(int arrMaxSize
) {maxSize
= arrMaxSize
;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
+ 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() {return (rear
+ maxSize
- front
) % maxSize
;}public int headQueue() {if (isEmpty()) {throw new RuntimeException("隊列空的,沒有數據~~");}return arr
[front
];}
}
public class CircleArrayQueueDemo {public static void main(String
[] args
) {System
.out
.println("測試數組模擬環形隊列的案例~~~");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): 查看隊列頭的數據");System
.out
.println();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("程序退出~~");}}
測試數組模擬環形隊列的案例~~~
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): 查看隊列頭的數據s
arr[0]=1
arr[1]=2
arr[2]=3
s(show): 顯示隊列
e(exit): 退出程序
a(add): 添加數據到隊列
g(get): 從隊列取出數據
h(head): 查看隊列頭的數據a
輸出一個數
4
隊列滿,不能加入數據~
s(show): 顯示隊列
e(exit): 退出程序
a(add): 添加數據到隊列
g(get): 從隊列取出數據
h(head): 查看隊列頭的數據g
取出的數據是1
s(show): 顯示隊列
e(exit): 退出程序
a(add): 添加數據到隊列
g(get): 從隊列取出數據
h(head): 查看隊列頭的數據g
取出的數據是2
s(show): 顯示隊列
e(exit): 退出程序
a(add): 添加數據到隊列
g(get): 從隊列取出數據
h(head): 查看隊列頭的數據s
arr[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): 查看隊列頭的數據
總結
以上是生活随笔為你收集整理的数据结构之稀疏数组队列的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。