稀疏数组
基本介绍
在我们存储又大量重复元素值的二维数组时,如果使用一般的二维数组可能会用大量重复元素
,这样就会浪费空间
。
当一个数组中大部分元素为0,或者为同一个值的数组时,可以使用稀疏数组来保存该数组。
五子棋的存储
这是一个15x15的棋盘,我们将用二维数组来表示它,0 表示空,1 表示黑子,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 1 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 2 1 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 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
我们把它保存成这样的结构
row col val
1 15 15 4
2 3 3 1
3 4 3 2
4 4 4 1
5 5 3 2
第一行 row 保存数组的行数,col 保存数组的列数,val 保存数组有效数值的个数
代码实现
二维数组存储
public class SparseArray {
private int[][] sparseArray; // 存储稀疏数组
public static void main(String[] args) {
// 创建一个原始的二维数组 15 * 15
// 0:表示没有棋子,1 表示 黑子 2 表示白子
int chessArr[][] = new int[15][15];
chessArr[3][3] = 1;
chessArr[4][3] = 2;
chessArr[4][4] = 1;
chessArr[5][3] = 2;
// 打印原始数组
for (int[] ints : chessArr) {
System.out.println(Arrays.toString(ints));
}
// 创建稀疏数组
SparseArray sparseArray = new SparseArray(chessArr);
sparseArray.print();
// 恢复二维数组
int arr[][] = sparseArray.getArray();
for (int[] ints : arr) {
System.out.println(Arrays.toString(ints));
}
}
public SparseArray(int[][] array){
// 获得有效的数组数值
int count = 0;
for (int i = 0; i < array.length; i++) {
for (int j = 0; j < array[0].length; j++) {
if (array[i][j] != 0){
count++;
}
}
}
// 创建稀疏数组
sparseArray = new int[count+1][3];
sparseArray[0][0] = array.length;
sparseArray[0][1] = array[0].length;
sparseArray[0][2] = count;
// 遍历二维数组将非零的值存放到稀疏数组
count = 0;
for (int i = 0; i < array.length; i++) {
for (int j = 0; j < array[i].length; j++) {
if (array[i][j] != 0){
count++;
sparseArray[count][0] = i;
sparseArray[count][1] = j;
sparseArray[count][2] = array[i][j];
}
}
}
}
public void print(){
for (int[] arr : sparseArray) {
System.out.println(Arrays.toString(arr));
}
}
// 返回稀疏数组
public int[][] getSparseArray() {
return sparseArray;
}
// 恢复二维数组
public int[][] getArray(){
int[][] arr = new int[sparseArray[0][0]][sparseArray[0][1]];
for (int i = 1; i < sparseArray.length; i++) {
arr[sparseArray[i][0]][sparseArray[i][1]] = sparseArray[i][2];
}
return arr;
}
}
// 稀疏数组
[15, 15, 4]
[3, 3, 1]
[4, 3, 2]
[4, 4, 1]
[5, 3, 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, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 2, 1, 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]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
一维数组存储
如果我想用一维数组存储,该怎么修改呢
我们可以把数组转换成下面这样的形式
col val
1 225 4
2 48 1
3 63 2
4 64 1
5 78 2
一维数组转换成稀疏数组
public SparseArray(int[] array){
int count = 0;
for (int i = 0; i < array.length; i++) {
if (array[i] != 0){
count++;
}
}
sparseArray = new int[count+1][2];
sparseArray[0][0] = array.length;
sparseArray[0][1] = count;
// 遍历一维数组将非零的值存放到稀疏数组
count = 0;
for (int i = 0; i < array.length; i++) {
if (array[i] != 0){
count++;
sparseArray[count][0] = i;
sparseArray[count][1] = array[i];
}
}
}
稀疏数组转换成一维数组
public int[] getLinearArray(){
int[] arr = new int[sparseArray[0][0]];
for (int i = 1; i < sparseArray.length; i++) {
arr[sparseArray[i][0]] = sparseArray[i][1];
}
return arr;
}
中国象棋的存储
存储中国象棋的棋盘是不是也能像五子棋一样呢?
稀疏数组
把中国象棋抽象成一维数组
int board[] = {
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,39,37,35,33,32,34,36,38,40,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,41,0,0,0,0,0,42,0,0,0,0,0,
0,0,0,43,0,44,0,45,0,46,0,47,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,27,0,28,0,29,0,30,0,31,0,0,0,0,
0,0,0,0,25,0,0,0,0,0,26,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,23,21,19,17,16,18,20,22,24,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
};
使用上面的稀疏数组类来出来这个数组
[256, 32]
[51, 39]
[52, 37]
[53, 35]
[54, 33]
[55, 32]
[56, 34]
[57, 36]
[58, 38]
[59, 40]
[84, 41]
[90, 42]
[99, 43]
[101, 44]
[103, 45]
[105, 46]
[107, 47]
[147, 27]
[149, 28]
[151, 29]
[153, 30]
[155, 31]
[164, 25]
[170, 26]
[195, 23]
[196, 21]
[197, 19]
[198, 17]
[199, 16]
[200, 18]
[201, 20]
[202, 22]
[203, 24]
长度为 256 的一维数组变为了长度为 2 * 33 的二维数组,那么轮到哪一方的走子以及棋局回合数又该怎么记录呢?
col val
1 225 4
2 16 1
3 32 0
4 48 1
5 63 2
6 64 1
7 78 2
修改稀疏数组结构,使第二行记录红子回合数,第三行记录黑子的回合数,这样长度就变为了 2 * 35
FEN串
中国象棋是又专门的记录规范的,一个局面可以简单地用一行“FEN格式串”来表示
rnbakabnr/9/1c5c1/p1p1p1p1p/9/9/P1P1P1P1P/1C5C1/9/RNBAKABNR w - - 0 1
初始局面下长度为69
由于它是文本格式的(只牵涉到很有限的几个字母、数字和符号),因此网上传递棋局就非常方便,FEN格式串有很多载体,通常的做法是把它保存成后缀为“.FEN”的文件。FEN文件是ASCII码文件,可以用任何文本编辑软件来建立和修改,也可以通过象棋棋谱软件来产生。
两种存储方式的比较
通过对比可以发现
- 稀疏数组在存储空间上基本达到最小。
- 稀疏数组通用性比较好
- 稀疏数组不方便更改