3.1 稀疏稀疏阵列数组
3.1.1 先看一个实际的需求
3.1.2 基本介绍
稀疏矩阵
3.1.3 应用实例
package com.datastruct.demo.structure.sparseArray;
public class SpareArray {
/** 打印数组
* @param array
*/
public static void printArray(int [][] array){
for (int [] row:array) {
for (int data:row) {
System.out.printf("%d\t",data);
}
System.out.println();
}
}
/** 获取二维数据中非0的个数,作为稀疏数组的[0][2]
* @param chessArr
* @return
*/
public static int getSum(int [][]chessArr) {
int sum = 0;
for (int i = 0; i< chessArr.length;i++){
for (int j = 0;j < chessArr[0].length;j++){
if (chessArr[i][j] != 0){
sum ++;
}
}
}
return sum;
}
/**
* 遍历二维数组,将非0的值存放到spareArr
*/
public static void setSparseArr(int [][]chessArr,int [][]sparseArr){
// 用于记录是第几个非0数据
int count = 1;
for (int i = 0; i< chessArr.length;i++){
for (int j = 0;j < chessArr[0].length;j++){
if (chessArr[i][j] != 0){
sparseArr[count][0] = i;
sparseArr[count][1] = j;
sparseArr[count][2] = chessArr[i][j];
count ++;
}
}
}
}
/** 稀疏数组转二维数组
* 稀疏数组的第一行为二维数组的大小,随后读取稀疏数组的随后几行并赋值给二维数组即可
*/
public static int[][] turnSparseArr(int [][]sparseArr){
// 根据稀疏数组的第一行创建一个数组
int [][]turnArray = new int[sparseArr[0][0]][sparseArr[0][1]];
for (int i = 1;i < sparseArr.length;i++){
turnArray[sparseArr[i][0]][sparseArr[i][1]] = sparseArr[i][2];
}
return turnArray;
}
public static void main(String[] args) {
// 创建一个原始的二维数组 11*11
// 0:表示没有棋子,1表示黑子,2表示白子
int [][]chessArr = new int[11][11];
chessArr[1][2] = 1;
chessArr[2][3] = 2;
System.out.println("原始的二维数据~");
printArray(chessArr);
int sum = getSum(chessArr);
// 创建对象的稀疏数组
int [][]sparseArr = new int[sum + 1][3];
// 给稀疏数组赋值(第一行记录二维数组的行列数,跟非零数)
sparseArr[0][0] = chessArr.length;
sparseArr[0][1] = chessArr[0].length;
sparseArr[0][2] = sum;
setSparseArr(chessArr,sparseArr);
// 输出稀疏数组
System.out.println();
printArray(sparseArr);
// 稀疏数组转二维数组
int [][]turnArray = turnSparseArr(sparseArr);
System.out.println();
printArray(turnArray);
}
}
3.2 队列
3.2.1 队列的一个使用场景
3.2.2 队列介绍
3.2.3 数组模拟队列思路
-
队列本身是有序列表,若使用数组的结构来存储队列的数据,则队列数组的声明如下图,其中maxSize是该队列的最大容量
-
因为队列的输出、输入是分别从前后端来处理,因此需要两个变量front和read分别记录队列前后端的下标,front会随着数据输出而改变,read则是随着数据输入而改变,如图所示
-
当我们将数据存入队列时为"addQueue",一般有两个步骤,思路如下
(1)将尾指针往后移:read+1 当front == read
(2)当尾指针rear小于队列的最大下边maxSize -1,则将数据存入rear所指的数组元素中,否则无法存入数据。rear==maxSize - 1 [队满]
代码实现
package com.datastruct.demo.structure.queue;
import java.util.Scanner;
/**
* 数组队列测试类
*/
public class ArrayQueueDemo {
public static void main(String[] args) {
ArrayQueue arrayQueue = new ArrayQueue(10);
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):查看队列头的数据");
//接收一个字符
key = scanner.next().charAt(0);
switch (key){
case 's':
arrayQueue.showQueue();
break;
case 'a':
System.out.println("输入一个数");
int value = scanner.nextInt();
arrayQueue.addQueue(value);
break;
case 'g':
try {
int res = arrayQueue.getQueue();
System.out.printf("取出的数据是%d\n",res);
}catch (Exception ex){
System.out.println(ex.getMessage());
}
break;
case 'h':
try {
int res = arrayQueue.headQueue();
System.out.printf("队列头数据是%d\n",res);
}catch (Exception ex){
System.out.println(ex.getMessage());
}
break;
case 'e':
scanner.close();
loop = false;
break;
default:
break;
}
}
}
}
上述代码存在一个问题:目前的数组使用一次就不能使用,没有达到复用的效果,因此我们可以改成环形的队列,取模%
3.2.4 数组模拟环形队列
代码实现
package com.datastruct.demo.structure.queue;
public class CircleQueue {
/**
* 最大容量
*/
private int maxSize;
/**
* 队列头front 就指向队列的第一个元素, 也就是说 arr[front] 就是队列的第一个元素
*/
private int front = 0;
/**
* 队列尾rear 指向队列的最后一个元素的后一个位置. 因为希望空出一个空间做为约定.(默认指向1)
*/
private int rear = 0;
/**
* 用于存放数据,模拟队列
*/
private int []array;
public CircleQueue(int maxSize){
this.maxSize = maxSize;
array = new int[maxSize];
}
/** 判断队列是否满
* @return
*/
public boolean isFull(){
return (rear + 1) % this.maxSize == front;
}
/** 判断队列是否空
* @return
*/
public boolean isEmpty(){
return rear == front;
}
/** 向队列加数据
* @param n
*/
public void addQueue(int n){
// 先判断是否队列满
if (isFull()){
System.out.println("队列已满,不能插入");
return;
}
// 尾指针后移
array[rear] = n;
// 将 rear 后移, 这里必须考虑取模
rear = (rear + 1) % maxSize;
}
/** 向队列取数据
* @return
*/
public int getQueue(){
// 判断队列是否空
if (isEmpty()){
System.out.println("队列空,不能取数据");
}
int value = array[front];
front = (front + 1) % maxSize;
return value;
}
/**
* 显示队列的所有数据
*/
public void showQueue(){
// 遍历
if (isEmpty()){
System.out.println("队列空的,没有数据");
return;
}
for (int i = front;i < this.size();i++){
System.out.printf("array[%d] = %d\n",i % maxSize,array[i % maxSize]);
}
}
/** 求出当前队列有效数据的个数
* @return
*/
public int size(){
return (rear + maxSize -front) % maxSize;
}
/**
* @return 显示队列的头数据(注意不是取数据)
*/
public int headQueue(){
if (isEmpty()){
System.out.println("队列空的,没有数据");
}
return array[front + 1];
}
}
package com.datastruct.demo.structure.queue;
import java.util.Scanner;
/**
* 数组队列测试类
*/
public class ArrayQueueDemo {
public static void main(String[] args) {
// 说明设置是4,但是其队列的有效数据是3
CircleQueue queue = new CircleQueue(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):查看队列头的数据");
//接收一个字符
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 ex){
System.out.println(ex.getMessage());
}
break;
case 'h':
try {
int res = queue.headQueue();
System.out.printf("队列头数据是%d\n",res);
}catch (Exception ex){
System.out.println(ex.getMessage());
}
break;
case 'e':
scanner.close();
loop = false;
break;
default:
break;
}
}
}
}