使用数组实现队列
什么是队列?
队列是一种数据存储的结构,实例化的队列就是一种数据容器,用特定的规则来存储数据的容器。队列遵循先进先出原则,一般可以使用数组和链表来实现队列,且队列的进队只从屁股rear开始,出列从front开始。
队列实现需要注意哪些?
队列必须的属性需要有实现数据存储的容器、队列的容量、rear以及front。方法需要有进队方法,以及出对方法。此外进队需要判断队列是否已满,出对判断队列是否已空等,这便是实现一个队列的基本关注点。此外,往细了考虑,什么情况是队列满了呢?初始时队列为空,rear与front均是-1,rear的取值范围是-1 到 maxSize-1.而front的取值范围也是-1到maxSize。队列满时则rear必须是maxSize-1且front!=rear,而队列为空时,则一定是rear=front时。
记录代码实现
class PQueue{
private static PQueue pQueue;
private int[] array;//声明一个数组,用作这个队列的容器
private int maxSize;//队列的大小
private int rear;//队列的后端,初始-1
private int front;//队列的前端-1(front永远指向队列的前一个数),初始-1
//初始化队列--禁止外部调用
private PQueue(int maxSize){
this.maxSize = maxSize;
array = new int[this.maxSize];
rear = -1;
front = -1;
}
//线程安全的单利模式
public static PQueue getInstance(int maxSize){
if(null == pQueue){
synchronized (PQueue.class){
pQueue = new PQueue(maxSize);
}
}
return pQueue;
}
//判断队列是否已满
public boolean isFull(){
return rear == maxSize-1?false:true && rear!=front;
}
//判断队列是否为空
public synchronized boolean isEmpty(){
return rear == front?false:true;
}
//队列中增加元素
public void addPQueue(int num){
//先判断队列已满
if(isFull()){
rear++;
array[rear]=num;
return;
}
System.out.println("队列已满,添加元素失败");
throw new RuntimeException("队列已满,添加元素失败");
}
//队列中删除元素--可能会有多个线程同时操作,需线程安全
public synchronized int getPQueue(){
//判断队列是否为空
if(isEmpty()){
front++;
return array[front];
}
System.out.println("队列为空,删除元素失败");
throw new RuntimeException("队列为空,删除元素失败");
}
//展示队列中所有元素
public int[] showPQueue(){
//数组长度为rear减去front,因front指向数组的前一个值
int[] realArray = new int[rear-front];
int index=0;//初始化realArray的下标。
for(int i=0;i<array.length;i++){
//将有效的数据加入到真实数组中
if(i>front && i<=rear){
realArray[index]=array[i];
index++;
}
}
return realArray;
}
}
队列的应用场景在哪?
1.最常见的就是排队系统,你必须保证先取号的人,最先被服务,这种常见的就是各个银行等。这里模拟下银行排队系统(线程通信并未实现,有线程安全风险)
代码如下
//模拟银行业务的线程A
class OperatorA implements Runnable{
PQueue pQueue = PQueue.getInstance(20);
@Override
public void run() {
while (pQueue.isEmpty()){
System.out.println("请"+pQueue.getPQueue()+"号客户前往A窗口办理业务!");
System.out.println("业务处理中。。。");
try {
Thread.currentThread().sleep(3000);//假设A窗口处理业务需要3秒钟
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
//模拟银行业务的线程B
class OperatorB implements Runnable{
PQueue pQueue = PQueue.getInstance(20);
@Override
public void run() {
while(pQueue.isEmpty()){
System.out.println("请"+pQueue.getPQueue()+"号客户前往B窗口办理业务!");
System.out.println("业务处理中。。。");
try {
Thread.currentThread().sleep(4000);//假设B窗口处理业务需要4秒钟
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
//模拟银行业务的线程C
class OperatorC implements Runnable{
PQueue pQueue = PQueue.getInstance(20);
@Override
public void run() {
while(pQueue.isEmpty()){
System.out.println("请"+pQueue.getPQueue()+"号客户前往C窗口办理业务!");
System.out.println("业务处理中。。。");
try {
Thread.currentThread().sleep(5000);//假设C窗口处理业务需要5秒钟
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
执行代码
PQueue pQueue = PQueue.getInstance(13);
//假设有13个人取了票在排队
pQueue.addPQueue(1);
pQueue.addPQueue(2);
pQueue.addPQueue(3);
pQueue.addPQueue(4);
pQueue.addPQueue(5);
pQueue.addPQueue(6);
pQueue.addPQueue(7);
pQueue.addPQueue(8);
pQueue.addPQueue(9);
pQueue.addPQueue(10);
pQueue.addPQueue(11);
pQueue.addPQueue(12);
pQueue.addPQueue(13);
//银行窗口开始工作
Thread threadA = new Thread(new OperatorA());
Thread threadB = new Thread(new OperatorB());
Thread threadC = new Thread(new OperatorC());
threadA.start();
threadB.start();
threadC.start();
执行结果
请1号客户前往A窗口办理业务!
业务处理中。。。
请2号客户前往C窗口办理业务!
业务处理中。。。
请3号客户前往B窗口办理业务!
业务处理中。。。
请4号客户前往A窗口办理业务!
业务处理中。。。
请5号客户前往B窗口办理业务!
业务处理中。。。
请6号客户前往C窗口办理业务!
业务处理中。。。
请7号客户前往A窗口办理业务!
业务处理中。。。
请8号客户前往B窗口办理业务!
业务处理中。。。
请9号客户前往A窗口办理业务!
业务处理中。。。
请10号客户前往C窗口办理业务!
业务处理中。。。
请11号客户前往A窗口办理业务!
业务处理中。。。
请12号客户前往B窗口办理业务!
业务处理中。。。
请13号客户前往C窗口办理业务!
业务处理中。。。