稀疏数组和队列:
稀疏数组
基本介绍:
当一个数组中大部分元素为0,或者为同一个值的数组时 可以使用稀疏数组来保存该数组
稀疏数组的处理方法是:
①记录数组一共有几行几列 有多少个不同的值
②把具有不同值的元素的行列及值记录在一个小规模数组中 从而缩小程序的规模
举例说明:
原始的二维数组->稀疏数组
二维数组转稀疏数组的思路
①遍历原始的二维数组 得到有效数据的个数sum
②根据sum就可以创建稀疏数组sparseArr int[sum+1][3]
③二维数组的有效数据存入到稀疏数组
稀疏数组转二维数组的思路
①先读取稀疏数组的第一行 根据第一行的数据 创建原始的二维数组 比如上图中的
chessArr2 = int[11][11]
②再读取稀疏数组后几行的数据 并赋给原始的二维数组即可
应用实例
public class xishushuzu {
public static void main(String[] args) {
//1.创建一个11*11的数组
int chessArr1[][] = new int[11][11];
chessArr1[1][2] = 1;
chessArr1[2][3] = 2;
System.out.println("原始的二维数组");
for (int[] row : chessArr1) {
for (int data : row)
System.out.print(data + "\t");
System.out.println();
}
//将二维数组转稀疏数组的思路
//1.先遍历二维数组 得到非0数据的个数
int count = 0;
for (int i = 0; i < chessArr1.length; i++) {
for (int j = 0; j < chessArr1[0].length; j++) {
if (chessArr1[i][j] != 0)
count++;
}
}
// System.out.println(count);
//2.创建对应的稀疏数组
int[][] xssz = new int[count + 1][3];
//给稀疏数组赋值
xssz[0][0] = 11;
xssz[0][1] = 11;
xssz[0][2] = 2;
int countF = 0;
//遍历二维数组 将非0值 存入稀疏数组中
for (int i = 0; i < chessArr1.length; i++) {
for (int j = 0; j < chessArr1[0].length; j++) {
if (chessArr1[i][j] != 0) {
countF++;
xssz[countF][0] = i;
xssz[countF][1] = j;
xssz[countF][2] = chessArr1[i][j];
}
}
}
//输出稀疏数组
System.out.println("稀疏数组");
for (int[] row : xssz) {
for (int data : row)
System.out.print(data + "\t");
System.out.println();
}
System.out.println("恢复后的二维数组:");
int[][] newA = new int[xssz[0][0]][xssz[0][1]];
for (int i = 1; i < xssz.length; i++) {
newA[xssz[i][0]][xssz[i][1]] = xssz[i][2];
}
for (int[] row : chessArr1) {
for (int data : row)
System.out.print(data + "\t");
System.out.println();
}
}
}
队列
①队列是一个有序链表 可以用数组或是链表来实现
②遵循先入先出原则 即 先存入的数据要先取出 后存入的数据要后取出
③队列本身是有序链表 若使用数组的结构来存储队列的数据 则队列数组的声明如下图 其中maxSize是该队列的最大容量
④因为队列的输入、输出是分别从前后端来处理 因此需要两个变量front以及rear分别记录队列前后端的下标 front会随着数据输出而改变 而rear则是随着数据输入而改变
⑤rear是队列最后(包含最后)
⑥front是队列最前元素(不含)
数组模拟队列
当我们存入队列时 成为"addQueue",addQueue的处理要有两个步骤:思路分析
①将指针往后移:rear+1 当front==rear[空]
②若队尾指针rear小于队列的最大小标maxSize-1 则将数据存入rear所指的数据元素中 则无法存入数据 rear==maxSize-1 [队列满]
③front和rear的默认值都是-1
代码:
import java.util.Scanner;
public class shuzumoniduilie {
public static void main(String[] args) {
ArrayQueue arrayQueue = new ArrayQueue(3);
char key = ' ';
Scanner scanner = new Scanner(System.in);
boolean loop=true;
//输出一个菜单
while(loop){
System.out.println("s:显示队列");
System.out.println("e:退出程序");
System.out.println("a:添加数据到队列");
System.out.println("g:从队列取出数据");
System.out.println("h:查看队列头的数据");
key = scanner.next().charAt(0);
switch (key){
case 's':
arrayQueue.show();
break;
case 'a':
System.out.println("请输入一个数:");
int v = scanner.nextInt();
arrayQueue.addQueue(v);
break;
case 'g':
try {
int res = arrayQueue.getQueue();
System.out.println(res);
} catch (Exception e) {
System.out.println(e.getMessage());
}
break;
case 'h':
try {
int res = arrayQueue.headQueue();
System.out.println(res);
} catch (Exception e) {
System.out.println(e.getMessage());
}
break;
case 'q':
scanner.close();
loop=false;
break;
}
System.out.println("退出");
}
}
}
class ArrayQueue{
private int maxSize;//数组最大容量
private int front;
private int rear;
private int[] arr;
//创建队列的构造器
public ArrayQueue(int maxSize) {
this.maxSize = maxSize;
arr = new int[maxSize];
front=-1;//指向队列头 指向队列头部的前一个位置
rear=-1;//指向队列尾 指向队列尾的数据(即就是队列的最后一个数据)
}
//判断队列是否满
public boolean isFull(){
return rear==maxSize-1;
}
//判断队列是为空
public boolean isEmpty(){
return rear==front;
}
//添加数据到队列
public void addQueue(int n){
//判断是否满
if(isFull()){
System.out.println("已满");
return;
}
rear++;
arr[rear]=n;
}
//获取队列的数据 出队列
public int getQueue(){
//判断是否空
if(isEmpty()){
throw new RuntimeException("空~");
}
front++;
return arr[front];
}
//显示队列的所有数据
public void show(){
if(isEmpty()){
System.out.println("没数据");
return;
}
for (int i = 0; i < arr.length; i++) {
System.out.print("arr["+i+"]:"+arr[i]+"\t");
}
System.out.println();
}
//显示队列的头部数据(不是取数据 只是显示)
public int headQueue(){
if(isEmpty()){
throw new RuntimeException("空~");
}
return arr[front+1];//front指向的是队列头的前一个位置 所以需要加1
}
}
目前存在的问题:
①目前数组使用一次就不能用 没有达到复用的效果
②将这个数组使用算法 改进成一个环形数组 取模%
数组模拟环形队列
对前面的数组模拟队列的优化 充分利用数组因此将数组看做是一个环形的(用%来实现)
分析说明
①尾索引的下一个为头索引时表示队列满 即将队列容量空出一个作为约定 这个在做判断队列满的时候 需要注意(rear+1)%maxSize==front 满
②rear==front 空
③front变量的含义更正为:front指向队列的第一个元素 即:arr[front]就是队列第一个元素
初始值默认为0
④rear变量的含义更正为:rear指向队列的最后一个元素的后一个位置 空出一个空间作为约定
初始值默认为0
⑤队列中有效数据的个数:(rear+maxSize-front)%maxSize
import java.util.Scanner;
public class xunhuanduilie {
public static void main(String[] args) {
CircleArray circleArray = new CircleArray(4);
//有效数据最大是3
char key = ' ';
Scanner scanner = new Scanner(System.in);
boolean loop=true;
//输出一个菜单
while(loop){
System.out.println("s:显示队列");
System.out.println("e:退出程序");
System.out.println("a:添加数据到队列");
System.out.println("g:从队列取出数据");
System.out.println("h:查看队列头的数据");
System.out.println("l:查看有效数据的个数");
key = scanner.next().charAt(0);
switch (key){
case 's':
circleArray.show();
break;
case 'a':
System.out.println("请输入一个数:");
int v = scanner.nextInt();
circleArray.addQueue(v);
break;
case 'g':
try {
int res = circleArray.getQueue();
System.out.println(res);
} catch (Exception e) {
System.out.println(e.getMessage());
}
break;
case 'h':
try {
int res = circleArray.headQueue();
System.out.println(res);
} catch (Exception e) {
System.out.println(e.getMessage());
}
break;
case 'q':
scanner.close();
loop=false;
break;
case 'l':
circleArray.show();
break;
}
System.out.println("退出");
}
}
}
class CircleArray{
private int maxSize;//数组最大容量
private int front;
private int rear;
private int[] arr;
//创建队列的构造器
public CircleArray(int maxSize) {
this.maxSize = maxSize;
arr = new int[maxSize];
front=0;//指向队列头 指向队列第一个元素 默认值0
rear=0;//指向队列尾 指向队列尾的后一个位置 默认值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("已满");
return;
}
arr[rear]=n;
rear = (rear+1)%maxSize;
}
//获取队列的数据 出队列
public int getQueue(){
//判断是否空
if(isEmpty()){
throw new RuntimeException("空~");
}
//先把front对应的值保存到一个临时变量
//front后移 考虑取模
//将临时保存的变量后移
int value = arr[front];
front = (front+1)%maxSize;
return arr[value];
}
//显示队列的所有数据
public void show(){
if(isEmpty()){
System.out.println("没数据");
return;
}
for (int i = front; i < front+size(); i++) {
System.out.print("arr["+i%maxSize+"]:"+arr[i%maxSize]+"\t");
}
System.out.println();
}
//显示队列的头部数据(不是取数据 只是显示)
public int headQueue(){
if(isEmpty()){
throw new RuntimeException("空~");
}
return arr[front];
}
//求出当前队列有效数据的个数
public int size(){
/*
比如 rear=1 front=0 maxSize=3
*/
return (rear+maxSize-front)%maxSize;
}
}