稀疏数组和队列
稀疏数组
假设我们有一个棋盘
我们可以看到,现在只有两个棋子在我们的棋盘上,虽然我们可以完全使用二维数组来保存整张棋盘,但是这样实在是太浪费空间了,这个时候我们就需要稀疏数组
当一个数组中大部分元素为0,或者为同一个值的数组时,可以使用稀疏数组来保存该数组。
稀疏数组的处理方法是:
-
记录数组一共有几行几列,有多少个不同的值
-
把具有不同值的元素的行列及值记录在一个小规模的数组中,从而缩小程序的规模
可以看到,我们可以使用一种全新的方式来保存数组
- 记录我们当前的数组里面有多少个不同的元素
- 标记处我们每个不同元素的位置
现在,一个 11 × 11 11 \times 11 11×11的二维数组就被我们缩减成了一个 3 × 3 3 \times 3 3×3的数组了
思路
二维数组 转 稀疏数组的思路
-
遍历 原始的二维数组,得到有效数据的个数num
-
根据num就可以创建稀疏数组sparseArr int[num + 1][3]1
- 将二维数组的有效数据存入稀疏数组
稀疏数组 转 原始数组的思路
-
先读取稀疏数组的第一行, 根据第一行的数据,创建原始的二维数组,比如上面的
chessArr2= int[11][11]
-
在读取稀疏数组后几行的数据,并赋给原始的二维数组即可
JAVA版代码实现
创建一个棋盘
代码如下
public class SparseArray {
public static void main(String[] args) {
// 创建一个原始的二维数组11*11
//0表示没有棋子,1表示黑子,2表示白子
int chessArr1[][] = new int[11][11];
chessArr1[1][2] = 1;
chessArr1[2][3] = 2;
// 输出棋盘
for(int[] row : chessArr1){
for(int data : row){
System.out.print(data + ",");
}
System.out.println();
}
}
}
把代码内不一样的部分转化成稀疏数组
// 计算二维数组中不同元素的个数然后返回相应的位置
public int countDifferent(int[][] chessArr){
int availableNumber = 0;
for(int y = 0;y<chessArr.length;y++){
for(int x = 0;x<chessArr[y].length;x++){
if(chessArr[y][x] !=0 ){
availableNumber++;
}
}
}
return availableNumber;
}
// 创建对应的稀疏数组
public int[][] createSpareArr(int[][] chessArr){
// 获取我们一共有多少元素不同
int differentElement = countDifferent(chessArr);
// 创建一个需要返回的稀疏数组
int spareArr[][] = new int[differentElement + 1][3];
// 给稀疏数组赋值
int id = 0;
for(int y = 0;y<chessArr.length;y++){
for(int x = 0;x<chessArr[y].length;x++){
// 发现新的数据
if(chessArr[y][x] !=0 ){
if(id==0){
// 给我们的稀疏数组创建棋盘的基础信息
spareArr[0][0] = chessArr[y].length;
spareArr[0][1] = chessArr.length;
spareArr[0][2] = differentElement;
// 因为我们的赋值操作放在了数组里面,所以覆盖了原来应该存的数据
// 所以我们数组中的第一行和第二行是特别的,需要手动处理
spareArr[1][0] = x;
spareArr[1][1] = y;
spareArr[1][2] = chessArr[y][x];
id++;
}else{
spareArr[id][0] = x;
spareArr[id][1] = y;
spareArr[id][2] = chessArr[y][x];
}
id++;
}
}
}
return spareArr;
}
这么多代码我们一共干了些什么事情呢?
- 创建了一个专门操控棋盘的class
- 创建了一个方法createSpareArr,能返回棋盘打包之后的数组(稀疏数组)
把稀疏数组转换成真正的数据
public int[][] spareArrToNormalArr(int[][] spareArr){
// 读取稀疏数组中的第一行数据来创建数列
int[][] chessArr2 = new int[spareArr[0][0]][spareArr[0][1]];
// 根据数据来依次恢复我们的数组
for(int i=1;i<spareArr.length;i++){
chessArr2[spareArr[i][1]][spareArr[i][0]] = spareArr[i][2];
}
return chessArr2;
}
可以看到我们现在的数据已经恢复了
-
先读取稀疏数组的第一行,根据第一行的数据,创建原始的二维数组
-
在读取稀疏数组后几行的数据,并赋给原始的二维数组即可。
Python版本代码实现
同理,我们也可以使用Python代码来复盘这些操作,但是无疑代码量会减少很多
创建棋盘
# 创建一个原始的二维数组11*11
# 0表示没有棋子,1表示黑子,2表示白子
self.chess_arr = []
temp_row = []
for y in range(11):
for x in range(11):
temp_row.append(0)
self.chess_arr.append(temp_row)
# 循环之后及得把temp_row清零
temp_row = []
当然这些代码亦可以使用python的列表推导式
# 列表推导式只需要一行就可以搞定
self.chess_arr = [[0 for _ in range(11)] for _ in range(11)]
设置棋盘上的棋子
# 设置放置棋子
def set_chess(self, *args):
# 目前传入的坐标为(x,y)的形式
for i in args:
self.chess_arr[i[1]][i[0]] = i[2]
a.set_chess([0, 1, 2], [1, 1, 1])
创建稀疏数组
def get_chess_arr(self):
return self.chess_arr
def create_spare_arr(self, chess_arr):
available_number = 0
spare_arr = []
for y in range(len(chess_arr)):
for x in range(len(chess_arr[y])):
if chess_arr[y][x] != 0:
available_number += 1
spare_arr.append([x, y, chess_arr[y][x]])
# 所有输出结束之后,在稀疏数组的头部插入列表信息
spare_arr.insert(0, [len(chess_arr[y]), len(chess_arr), available_number])
print(available_number)
for i in spare_arr:
print(i)
把稀疏数组转换成正常数组
def spare_to_list(self, spare_arr):
restore_arr = [[0 for _ in range(spare_arr[0][1])] for _ in range(spare_arr[0][0])]
for i in range(1,len(spare_arr)):
restore_arr[spare_arr[i][1]][spare_arr[i][0]] = spare_arr[i][2]
return restore_arr
可以看到此时,我们的python也完成了转化
为什么这里是spareArr int[num + 1][3]而不是spareArr int[num + 1]呢?
因为我们需要的是一个二维数组,存入数量的同时还要存入数据的坐标以及状态,内容大概长这样:
[ (x,y,棋子的颜色),(x,y,棋子的颜色) ] ↩︎