3 队列
队列是一个有序列表,可以用数组或者链表来实现。
队列的特点是先进先出。即:先存入队列的数据,要先取出。后存入的要后取出。
3.1 用数组模拟队列
队列的最大容量定义为maxSize。
因为队列的输入和输出是分别从前后端来处理,因此需要front和rear分别记录队列的前后端的下标,front会随着数据输出而改变,而rear会随着数据输入而改变。
用数组模拟队列,这种单项队列,是一次性的,添加满了就不能再利用了。
而环形队列可以循环使用。
package www.codejiwei.practice;
import java.util.Scanner;
public class ArrayQueueTest2 {
public static void main(String[] args) {
ArrayQueue2 queue = new ArrayQueue2(3);
Scanner scanner = new Scanner(System.in);
boolean loop = true;
do {
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): 查看队列头的数据");
char key = scanner.next().charAt(0);
switch (key){
case 's':
queue.showQueue();
break;
case 'e':
loop = false;
break;
case 'a':
System.out.println("请输入一个数:");
int num = scanner.nextInt();
queue.addQueue(num);
break;
case 'g':
try {
int getNum = queue.getQueue();
System.out.println("取数的数据是:"+getNum);
} catch (Exception e) {
System.out.println(e.getMessage());
}
break;
case 'h':
try {
int head = queue.headQueue();
System.out.println("队列头数据是:"+head);
} catch (Exception e) {
System.out.println(e.getMessage());
}
break;
}
}while (loop);
}
}
class ArrayQueue2{
private int maxSize;//队列的最大长度
private int front;//头指针
private int rear;//尾指针
private int[] arr;//队列数组
public ArrayQueue2(int maxSize) {
this.maxSize = maxSize;
arr = new int[maxSize];
front = -1;//头和尾初始化为-1
rear = -1;
}
//判断队列是否空
public boolean isEmpty(){
return front == rear;
}
//判断队列是否满
public boolean isFull(){
return maxSize == rear + 1;
}
//向队列添加数据
public void addQueue(int data){
//添加数据首先判断是否满
if (isFull()){
System.out.println("队列满,无法添加数据");
return;
}
rear++;
arr[rear] = data;
}
//显示队列数据
public void showQueue(){
//显示队列数据先判断队列是否空
if (isEmpty()){
System.out.println("队列空,无法显示数据");
return;
}
for (int i = 0; i < rear + 1; i++) {
System.out.println("arr["+i+"] = "+arr[i]);
}
}
//数据出队列
public int getQueue(){
//数据出队列先判断队列是否空
if (isEmpty()){
throw new RuntimeException("队列空,无法取出数据");
}
return arr[++front];
}
//显示队列头数据
public int headQueue(){
//显示队列头数据先判断队列是否为空
if (isEmpty()){
throw new RuntimeException("队列空,无头数据");
}
return arr[front + 1];
}
}
3.2 环形数组模拟队列
--(1)如何声明一个环形数组表示的队列呢?
class CirCleArrayQueue{
private int maxSize; //环形数组表示的队列的最大容量,注意!真正的容量为maxSize-1
private int[] arr ; //用数组表示队列
private int front ; //头指针
private int rear; //尾指针
public CirCleArrayQueue(int maxSize){
this.maxSize = maxSize;
arr = new int[this.maxSize];
front = 0;
rear = 0;
}
//判断队列空
//判断队列满
//数据入队列
//数据出队列
//显示队列头数据
//遍历队列(求队列中有效数据的个数)
}
--(2)如何判断队列为空?
public boolean isEmpty(){
return front == rear;
}
--(3)如何判断队列满?
public boolean isFull(){
return (rear + 1) % maxSize = front;
}
--(4)数据如何添加到队列?
public void addQueue(int value){
//判断队列是否满
if(isFull()){
sout("队列满");
return
}
arr[rear] = value;
rear = (rear + 1) % maxSize;
}
--(5)数据如何从队列中取出?
public int getQueue(){
//判断队列是否空
if(isEmpty()){
throw new RuntimeExecption("队列空");
}
int value = arr[front];
front = (front + 1) % maxSize;
return value;
}
--(6)遍历队列
public void listQueue(){
//判断队列是否空
if(isEmpty()){
sout("队列空");
return;
}
for(int i = front; i < front + size ; i++){
sout("arr[" + i % maxSize + "] = " + arr[i % maxSize]);
}
}
//求队列中有效数据的个数
public int size(){
return (rear - front + maxSize) % maxSize;
}
-
详细的代码分析如下:
需要注意的是取模!!!
package www.codejiwei.queue;
import java.util.Scanner;
public class CircleArrayQueueDemo {
public static void main(String[] args) {
CircleArrayQueue queue = new CircleArrayQueue(4);
Scanner scanner = new Scanner(System.in);
boolean flag = true;
while (flag){
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): 查看队列头的数据");
char key = scanner.next().charAt(0);
switch (key){
case 's':
queue.showQueue();
break;
case 'e':
System.out.println("是否确认退出?(Y/N)");
char exit = scanner.next().charAt(0);
if (exit == 'Y' || exit == 'y'){
flag = false;
break;
}
case 'a':
System.out.println("添加一个数据:");
int num = scanner.nextInt();
queue.addQueue(num);
break;
case 'g':
try {
int res = queue.getQueue();
System.out.println("取出的数据是"+res);
}catch (Exception e){
System.out.println(e.getMessage());
}
break;
case 'h':
try {
int headN = queue.headQueue();
System.out.println("队列头的数据是:"+headN);
}catch (Exception e){
System.out.println(e.getMessage());
}
break;
}
}
}
}
class CircleArrayQueue{
private int maxSize;//maxSize是4!!,但是表示能存3个数据,因为最后一个位置是作为约定
private int head;
private int tail;
private int[] arr;
public CircleArrayQueue(int maxSize) {
this.maxSize = maxSize;
head = 0;
tail = 0;
arr = new int[this.maxSize];
}
//判断队列是否满
public boolean isFull(){
/*
判断队列满是根据(tail + 1)% maxSize= head;即尾索引的下一个取模maxSize等于头索引
为什么呢?
如果此时队列满了,那么tail = 3 + 1 % 4 = 0;
*/
return (tail + 1) % maxSize == head;
}
//判断队列是否空
public boolean isEmpty(){
return head == tail;
}
//向队列添加数据
public void addQueue(int data){
if (isFull()){
System.out.println("队列满了,不能添加数据~~");
return;
}
arr[tail] = data;
//添加数据取模,使得数据到最后,通过取模回到前面的空位置
tail = (tail + 1) % maxSize;
}
//出队列
public int getQueue(){
if (isEmpty()){
throw new RuntimeException("队列空,不能取出数据");
}
int value = arr[head];
//取出数据,当去到最后时队列空了,通过取模使得头指针,回到最初的0位置
head = (head + 1) % maxSize;
return value;
}
//显示队列的所有数据
public void showQueue(){
if (isEmpty()){
System.out.println("队列为空,没有数据~");
return;
}
for (int i = head; i < head + size(); i++) {
System.out.println("arr[" + i % maxSize + "] = " + arr[i % maxSize]);
}
}
//求处当前队列有效数据的个数
public int size(){
// return (tail + maxSize - head) % maxSize;
/*为什么head和tail都是动态的了,有效个数还不能是tail - head呢?
初始:tail = 0;head = 0;maxSize = 4(实际存放3个数据)
这是因为当添加一个元素,tail = 1;head = 0;size = 1 - 0
此时取出一个元素,tail = 1; head = 1;size = 0 - 1
此时查看队列数据为没有元素(tail == head),也对;查看队列头元素,显示没有也对。
再添加2个元素,此时tail = 3,head = 1,size = 3 - 1
再添加1个元素,此时tail = 0(3 + 1 % 4),head = 1;size = 0 - 1;此时虽然(tail != head),但是for循环进不去,无法显示数据。
那么如果改为老师的size呢?
最后一步:此时的tail = 0,head = 1,size = 3(0 + 4 - 1 % 4),此时for循环是能进去的!
*
*/
return tail - head;
}
//显示队列的头数据
public int headQueue(){
if (isEmpty()){
throw new RuntimeException("队列为空,没有头数据");
}
return arr[head];
}
}