连续指地址的连续
非线性结构没有一对一的线性关系
稀疏数组(sparsearray)
- 当一个数组中有很多重复的元素,可以使用稀疏数组进行压缩
第一行表示数组的行列数以及不是0的元素的数量
[1]表示第一个有效数据
二维数组与稀疏数组
二维数组转稀疏数组
- 遍历原始的二维数组,得到有效数据元素数sum
- 得到稀疏数组 sparseArr int[sum+1] [3]
- 将有效数据存入稀疏数组
稀疏数组转二维数组
- 先读取稀疏数组的第一行,创建原始的二维数组
- 读稀疏数组中的数据,将有效数据赋值给二维数组
对列
特点:有序列表,先入先出
数组模拟队列
利用front随输出改变,rear随输入改变的特性,进行代码实现(如下)
此时:front代表第一个元素的前一个位置,rear就表示最后一个元素的下标
package com.Eeeeye.queue;
import java.util.Scanner;
public class ArrayQueueDemo {
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(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 e) {
System.out.println(e.getMessage());
}
break;
case 'h':
try {
int res = arrayQueue.getQueue();
System.out.printf("表头的数据是%d\n", res);
} catch (Exception e) {
System.out.println(e.getMessage());
}
break;
case 'e':
scanner.close();
loop = false;
System.out.println("程序退出");
break;
default:
break;
}
}
}
}
class ArrayQueue {
private int maxSize;
private int front;
private int rear;
private int[] arr;
//创建队列的构造器
public ArrayQueue(int arrMaxSize) {
maxSize = arrMaxSize;
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("队列满");
} else {
rear++;//++rear可以吗
arr[rear] = n;
}
}
public int getQueue() {
if (isEmpty()) {
System.out.println("队列为空");
throw new RuntimeException("队列为空");
}
front++;//相当于将队列头往队列尾的方向移动一位
//原先的队列头被取出
return arr[front];
}
public void showQueue() {
if (isEmpty()) {
System.out.println("队列为空");
return;
}
for (int i = 0; i < arr.length; i++) {//该处存在缺陷,实际上无法真正取出数据
System.out.printf("arr[%d] = %d\n", i, arr[i]);
}
}
}
但也是由于只利用这一特性,该数组在消耗完可使用的规格后,不可再复用(即使使用add方法)
优化 环形队列
分析:
- front指向第一个元素,也就是arr[front]是队列的第一个元素
- rear指向最后一个元素的后一个位置,因为希望预留一个空间(这是一种约定)进行环形处理
- *由于数组的特性(下标从0开始):front 的下标某种意义上代表着已输出的元素的个数,而此时的rear则代表着最后一位元素的上边界,也就是**存入过多少元素(*在第一轮中,在第二轮中则是rear+maxsize)
- rear,front的初始值都为0
- 判断队列满:(rear+1)%maxsize == front;
- 判断队列空:rear == front;
- 判断队列中的有效数据的个数:(rear+maxsize-front) % maxsize
代码实现
package com.Eeeeye.queue;
import java.util.Scanner;
public class CircleArrayQueueDemo {
public static void main(String[] args) {
CircleArray arrayQueue = new CircleArray(4);//因为预留一个位置,故实际只有3个位置
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 e) {
System.out.println(e.getMessage());
}
break;
case 'h':
try {
int res = arrayQueue.getQueue();
System.out.printf("表头的数据是%d\n", res);
} catch (Exception e) {
System.out.println(e.getMessage());
}
break;
case 'e':
scanner.close();
loop = false;
System.out.println("程序退出");
break;
default:
break;
}
}
}
}
class CircleArray {
private int maxSize;
private int front;//第一个元素
private int rear;//最后一个元素的后一个位置
private int[] arr;
public CircleArray(int arrMaxSize) {
maxSize = arrMaxSize;
arr = new int[maxSize];
}
public boolean isFull() {
return (rear + 1) % maxSize == front;
}
public boolean isEmpty() {
return rear == front;
}
public void addQueue(int n) {
if (isFull()) {
System.out.println("队列满");
} else {
arr[rear] = n;//此时不用先自加,因为rear已指向最后一个元素的后一个位置
rear = (rear + 1) % maxSize;//防止数组下标越界
}
}
public int getQueue() {
if (isEmpty()) {
System.out.println("队列为空");
throw new RuntimeException("队列为空");
}
//此时不可直接返回arr[front],因为需要先对front的值进行取出,再对front进行改变
int value = arr[front];//此时front指向队列的第一个元素
front = (front + 1) % maxSize;//防止数组下标越界
return value;//先利用变量储存front,最后再返回
}
public void showQueue() {
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;
}
public int headQueue(){
if (isEmpty()) {
throw new RuntimeException("队列为空");
}
return arr[front];//区别于前面的front + 1
}
}