在实际编程中,我们经常会遇到这样的场景:一个二维数组中大部分元素都是0(或者是同一个值),只有少部分元素有不同值。这种情况下,如果我们直接存储整个二维数组,会造成极大的空间浪费。这时候,我们就可以使用稀疏数组来解决这个问题。
稀疏数组的处理方法是:
public class SparseArray {
public static void main(String[] args) {
// 创建原始二维数组 11*11
int arrays[][] = new int[11][11];
// 初始化几个值
arrays[1][2] = 1;
arrays[2][3] = 2;
arrays[5][6] = 2;
// 输出原始二维数组
System.out.println("原始二维数组:");
for(int row[] : arrays) {
for(int data : row) {
System.out.printf("%d\t", data);
}
System.out.println();
}
// 统计非0值的个数
int sum = 0;
for(int i = 0; i < 11; i++) {
for(int j = 0; j < 11; j++) {
if(arrays[i][j] != 0) {
sum++;
}
}
}
// 创建稀疏数组
int sparse[][] = new int[sum + 1][3];
// 记录原始数组的行列和有效数据个数
sparse[0][0] = 11;
sparse[0][1] = 11;
sparse[0][2] = sum;
// 将非0的值存入稀疏数组
int count = 0;
for(int i = 0; i < 11; i++) {
for(int j = 0; j < 11; j++) {
if(arrays[i][j] != 0) {
count++;
sparse[count][0] = i;
sparse[count][1] = j;
sparse[count][2] = arrays[i][j];
}
}
}
// 输出稀疏数组
System.out.println("\n转换后的稀疏数组:");
for(int row[] : sparse) {
for(int data : row) {
System.out.printf("%d\t", data);
}
System.out.println();
}
// 还原二维数组
int newarrays[][] = new int[sparse[0][0]][sparse[0][1]];
for(int i = 1; i < sparse.length; i++) {
newarrays[sparse[i][0]][sparse[i][1]] = sparse[i][2];
}
// 输出还原后的二维数组
System.out.println("\n还原后的二维数组:");
for(int row[] : newarrays) {
for(int data : row) {
System.out.printf("%d\t", data);
}
System.out.println();
}
}
}
循环队列是一种线性数据结构,它的特点是把队列的首尾相连,形成一个环。这样可以更有效地利用数组空间,避免假溢出的问题。
class CircleArray {
private int maxSize;
private int front;
private int rear;
private int[] arr;
public CircleArray(int maxsize) {
maxSize = maxsize;
arr = new int[maxSize];
// front和rear初始值为0
}
// 判断队列是否已满
public boolean IsFulled() {
return (rear + 1) % maxSize == front;
}
// 判断队列是否为空
public boolean IsEmpty() {
return rear == front;
}
// 添加数据到队列
public void AddQueue(int n) {
if(IsFulled()) {
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 int HeadQueue() {
if(IsEmpty()) {
throw new RuntimeException("队列空");
}
return arr[front];
}
// 显示队列所有数据
public void ListQueue() {
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;
}
}
[ ][ ][ ][ ][ ] maxSize = 5
↑
f,r
说明:
- front = 0, rear = 0
- 队列为空
添加元素 1, 2, 3:
[1][2][3][ ][ ]
↑ ↑
f r
说明:
- front = 0
- rear = 3
- 有效元素个数 = 3
[1][2][3][4][ ]
↑ ↑
f r
说明:
- 最后一个位置必须空出来
- 满队列条件:(rear + 1) % maxSize == front
初始:
[1][2][3][4][ ]
↑ ↑
f r
出队一个元素后:
[ ][2][3][4][ ]
↑ ↑
f r
说明:
- front = (front + 1) % maxSize
初始:
[1][2][3][4][ ]
↑ ↑
f r
出队两个元素后:
[ ][ ][3][4][ ]
↑
f
↑
r
再添加元素5:
[5][ ][3][4][ ]
↑
f
↑
r
说明:
- 通过取模运算实现空间复用
public boolean IsFulled() {
return (rear + 1) % maxSize == front;
}
示意图:
[1][2][3][4][ ]
↑ ↑
f r
- rear的下一个位置是front时,队列满
public boolean IsEmpty() {
return rear == front;
}
示意图:
[ ][ ][ ][ ][ ]
↑
f,r
- front和rear指向同一位置时,队列空
public int Size() {
return (rear + maxSize - front) % maxSize;
}
示意图:
[5][ ][3][4][ ]
↑
f
↑
r
计算过程:
1. rear = 1
2. front = 2
3. maxSize = 5
4. (1 + 5 - 2) % 5 = 4 % 5 = 4
1. 初始状态:
[ ][ ][ ][ ][ ]
↑
f,r
2. 添加1:
[1][ ][ ][ ][ ]
↑ ↑
f r
3. 添加2:
[1][2][ ][ ][ ]
↑ ↑
f r
4. 添加3:
[1][2][3][ ][ ]
↑ ↑
f r
1. 初始状态:
[1][2][3][ ][ ]
↑ ↑
f r
2. 出队一个元素:
[ ][2][3][ ][ ]
↑ ↑
f r
3. 添加新元素4:
[4][2][3][ ][ ]
↑ ↑
f r
稀疏数组的优点:
循环队列的优点:
实际应用场景: