写在前面
稀疏数组
- 当一个数组中大部分元素时0,或为同一个值,例如五子棋棋盘,使用稀疏数组处理数组中没有意义的数据
- 记录数组一共几行几列,有多少个不同值;把具有不同值的元素的行列及值记录在一个小规模的数组中
- 自己的理解,通过协议的方式,固定存值的模型,例如[0][1]存总行数、[0][2]存总列数,[0][3]存总值数;[1][1]存行、[1][2]存列、[1][3]存值等等
代码实现
//创建存储的文件
String fileStr = "/Users/apple/Desktop/java/java-dataStructure/sparse-Array/src/array.txt"
File file = new File(fileStr)
file.createNewFile()
//创建原始二维数组 0无棋子,1黑,2蓝
int[][] chessArr = new int[11][11]
chessArr[1][2] = 1
chessArr[2][3] = 2
//将二维数组转换为稀疏数组
//遍历二维数组,记录相关数据
int sum = 0
for (int i = 0
for (int j = 0
if (chessArr[i][j] != 0) {
sum ++
}
}
}
//创建稀疏数组
int[][] sparseArr = new int[sum + 1][3]
//赋值
sparseArr[0][0] = chessArr.length
sparseArr[0][1] = chessArr[0].length
sparseArr[0][2] = sum
//遍历chessArr数组,存数据
//count记录第几个数据
int count = 0
for (int i = 0
for (int j = 0
if (chessArr[i][j] != 0) {
count ++
sparseArr[count][0] = i
sparseArr[count][1] = j
sparseArr[count][2] = chessArr[i][j]
}
}
}
//存稀疏数组
BufferedWriter writer = new BufferedWriter(new FileWriter(file))
for (int i = 0
for (int j = 0
if (i == sparseArr.length - 1 && j == sparseArr[0].length) {
writer.write(sparseArr[i][j] + "")
} else {
writer.write(sparseArr[i][j] + ",")
}
}
}
writer.close()
//读出数组,一维变二维
BufferedReader reader = new BufferedReader(new FileReader(file))
String resStr = reader.readLine()
reader.close()
String[] splitStr = resStr.split(",")
int[][] recoverSparseArr = new int[sum + 1][3]
//记录行数
int recoverCount = 0
for (int i = 0
recoverSparseArr[recoverCount][i % 3] = Integer.parseInt(splitStr[i])
if (i % 3 == 2) {
//每行三列,也就是说每三个要换一行
recoverCount ++
}
}
//将稀疏数组恢复成原始数组
int rowCount = recoverSparseArr[0][0]
int colCount = recoverSparseArr[0][1]
int valueCount = recoverSparseArr[0][2]
int[][] recoverChessArr = new int[rowCount][colCount]
int row = 0
int col = 0
int value = 0
for (int i = 1
row = recoverSparseArr[i][0]
col = recoverSparseArr[i][1]
value = recoverSparseArr[i][2]
recoverChessArr[row][col] = value
}
队列
- 有序列表,可以用数组或者链表来实现;先进先出
取模
可以实现循环和情况归一
环形数组实现队列
- 思路理解,通过取模的方式实现循环的效果,由于要保证
front
和rear
两个指向头尾的指标,都要一直变动,而且不能相等,因此要预留一个空间作为约定,rear+1
不能超过maxSize
,所以实际队列大小是maxSize
减1
front
队列头,负责取第一个值,0开始,永远指向有值的索引,通过(front + 1) % maxSize
来判断,front + 1
保证每次取完数据后都会向后移动,且当front == maxSize - 1
时,会自动跳到0
;rear
同理,但是其中要保证,raer
负责添加值,指向的地方永远没有值
- 队列满条件
(rear + 1) % maxSize == front
,如果队列满,根据循环数组的前提,front
在头,rear
在尾,rear
再加1就要回到头部与front
相等了
- 队列的有效数据个数
(rear - front + maxSize) % maxSize
,当rear > front
时,有效数据个数就是rear - front
,例如0 1 2 3
,rear
指向没有值的3
索引,那个数就是3 - 0 = 3
个;而rear < front
时,从头到尾front - rear
的部分是永远没有值的(假定数值是从左到右放的,那么当rear < front
时,也就是front
在rear
的左边),那么也就是说maxSize - (front - rear) = raer + maxSize - front
是有值的部分。而与maxSize
取模是将两种情况归一了,当rear - font > 0
时,就是比maxSize
多出来的那部分,就是模,也就是个数;当rear - front < 0
时,再有maxSize - (front - rear)
,就是减去没有值的部分,再取模,就是个数
- 遍历数据从
front
开始到front+size()
结束,因为要从当前头部front
开始取,到size()
结束;索引值i % maxSize
,循环找到当前值的位置
class ArrayCycleQueue {
private int maxSize;
private int front;
private int rear;
private int[] arr;
public ArrayCycleQueue(int maxSize) {
this.maxSize = maxSize + 1;
arr = new int[this.maxSize];
front = 0;
rear = 0;
}
public boolean isFull() {
return (rear + 1) % maxSize == front;
}
public boolean isEmpty() {
return rear == front;
}
public void addQueue(int n) {
if (isFull()) {
System.out.println("Queue is full");
return;
}
arr[rear] = n;
rear = (rear + 1) % maxSize;
}
public int getQueue() {
if (isEmpty()) {
throw new RuntimeException("Queue is empty");
}
int value = arr[front];
front = (front + 1) % maxSize;
return value;
}
public void showQueue() {
if (isEmpty()) {
System.out.println("Queue is empty");
return;
}
for (int i = front; i < front + size(); i++) {
System.out.println("arr[" + i % maxSize + "]" + " = " + arr[i % maxSize]);
}
}
public int size() {
return (rear + maxSize - front) % maxSize;
}
public int headQueue() {
if (isEmpty()) {
throw new RuntimeException("Queue is empty");
}
return arr[front];
}
}