队列
思路:使用数组实现
- 有关队列的描述
1.队头与队尾: 允许元素插入的一端称为队尾,允许元素删除的一端称为队头。
2.入队:队列的插入操作。
3.出队:队列的删除操作。
- 单向队列
front是队列最前元素(不含),rear是队列最后元素(含)
- 代码实现
public class Arrayqueue {
private int front;
private int rear;
private int arr[];
private int Maxsize;
public Arrayqueue() {
}
public Arrayqueue(int Maxsize) {
this.Maxsize = Maxsize;
arr = new int[Maxsize];
front = -1;//指向队列头前一个数据,数组下标从0开始
rear = -1;//指向队列尾,即最后一个数据
}
public boolean isEmpty() {
return front == rear;
}
public boolean isFull() {
return rear == Maxsize-1;
}
public void addValue(int n) {
if(isFull()) {
System.out.println("队列满,无法添加");
return;
}
rear++;//尾指针移动
arr[rear] = n;
}
public int getValue() {
if(isEmpty()) {
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]);
}
}
//显示队列的头数据
public int showhead() {
if(isEmpty()) {
throw new RuntimeException("队列空,无法显示头数据");
}
// front++;
return arr[front+1];
}
}
这里使用front+1而不是front++的原因:
自增和自减对本身的值会进行改变 ,而变量+1或-1 没有对本身的值进行改变。
单向队列的缺点:使用单向队列存储数据并取出后,无法再对原来的位置进行存储。
- 循环队列
思路:把队列的尾和头接在一起形成一个环,这样当发生假溢出时,尾指针可以跳到数组的开始,重复利用那些已经从队列里删掉的存储单元。
rear是指向队列中最后元素的后一个位置。
重点:
在判断是否为满的时候,预留一个空间,产生假满:
(rear + 1) % Maxsize == front;
//这里使用取模的原因是:front和rear初始化为0,Maxsize为3,当数组长度为3时,我们往其中添加两个元素,所以front=0,rear=2,这时候,我们添加第三个元素是加不了的,将rear=2代入上式得到rear=front,此时就预留一个空间了。
在单向队列中判断是否为满是这样的:
rear = Maxsize - 1;
添加数据时rear的操作:
rear = (rear + 1) % Maxsize;
//rear++;此操作数组有可能越界,这里使用取模使得rear可以回到原来使用过的位置
循环队列中有效数据的个数:
(rear + Maxsize - front) % Maxsize
- 代码实现
public class CircleArrayqueue {
// front是队列第一个元素(含),rear是队列倒数第二元素(不含)
private int front;
private int rear;
private int arr[];
private int Maxsize;
public CircleArrayqueue() {
}
public CircleArrayqueue(int Maxsize) {
this.Maxsize = Maxsize;
arr = new int[Maxsize];
// front = 0;指向队列第一个数据,数组下标从0开始
// rear = 0;指向队列倒数第二
}
public boolean isEmpty() {
return front == rear;
}
// 预留一个空间,产生"假满"
public boolean isFull() {
return (rear + 1) % Maxsize == front;
// rear = Maxsize-1;
}
public void addValue(int n) {
if (isFull()) {
System.out.println("队列满,无法添加");
return;
}
// 直接将数据加入
arr[rear] = n;
// rear++;此操作数组有可能越界
rear = (rear + 1) % Maxsize;
}
public int getValue() {
if (isEmpty()) {
throw new RuntimeException("队列空,无法获取");
}
// 此时front是指向队列的第一个元素
// 1.先把front的值保留到一个临时变量
// 2.将front后移,考虑取模
// 3.返回临时变量
int value = arr[front];
front = (front + 1) % Maxsize;
return value;
}
public void showQueue() {
if (isEmpty()) {
System.out.println("队列空");
return;
}
// 从front开始遍历,遍历多少个元素
for (int i = front; i < front + getSize(); i++) {
System.out.printf("arr[%d]=%d\n", i % Maxsize, arr[i % Maxsize]);
}
//这里输出数组时下标不是从i开始的原因:i有可能超过数组的长度,即越界
//假设Maxsize=3,front=2,rear=1,front+getSize()=4;根据循环条件,因为预留了一个空间,
//所以此时数组只有索引为0和2的元素,如果直接输出i,则会越界
}
// 求出当前队列有效数据的个数
public int getSize() {
return (rear + Maxsize - front) % Maxsize;
}
// 显示队列的头数据
public int showhead() {
if (isEmpty()) {
throw new RuntimeException("队列空,无法显示头数据");
}
// front++;
return arr[front];
}
}