Java数据结构学习Day1_队列_用数组模拟队列以及环形队列
队列
队列Queue
1.实际上是一个有序列表,可以用数组或者是链表来实现
2.遵循先进先出的原则(与栈相反,栈为先进后出)
3.示意图
数组模拟队列
一般队列
MaxSize为该队列的最大容量,两个变量rear和front分别标记队列前端和后端的位置,有元素出队时front+=1,有元素入队时rear+=1
思路分析:
1.有元素入队时rear+1,当front == rear时说明该队列为空
2.尾指针rear<MaxSize-1(最大的下标)时可以存进元素,队列不满,当rear == MaxSize时,队列满,无法存入元素
数组实现队列的问题:
1.目前数组使用一次就不能复用
代码实现:
package Ivan.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': //添加数据
try {
System.out.println("请输入一个数字");
int value = scanner.nextInt();
arrayQueue.addQueue(value);
}catch (Exception e){
System.out.println(e.getMessage());
}
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': //查看队列头部的数据e
try{
int res = arrayQueue.headQueue();
System.out.printf("队列头部数据是%d\n",res);
}catch (Exception e){
System.out.println(e.getMessage());
}
break;
case 'e': //退出命令
System.out.println("程序退出");
scanner.close();
loop = false;
break;
default:
break;
}
}
}
}
//使用数组模拟队列
class ArrayQueue{
private int maxSize; //表示最大容量
private int front; //表示头指针
private int rear; //表示尾指针
private int[] arr; //用于存放数据,模拟队列
//创建队列构造器
public ArrayQueue(int arrMaxSize){
maxSize = arrMaxSize;
rear = -1; //指向队列尾部,指向队列尾部的数据
front = -1; //指向队列头部,front是指向队列头部的前一个位置,之后取数据需要先+1
arr = new int[maxSize];
}
//判断队列是否为满
public boolean isFull(){
return rear == maxSize-1;
}
//判断队列是否为空
public boolean isEmpty(){
return rear == front;
}
//添加数据到队列
public void addQueue(int n){
//判断队列是否未满
if (isFull()){
throw new RuntimeException("队列已经满了");
}
rear++;
arr[rear] = n;
}
//获取队列的数据,出队列
public int getQueue(){
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 headQueue(){
if (isEmpty()){
throw new RuntimeException("队列为空,没有数据");
}
return arr[front + 1];
}
}
环形队列
优化:
1.将这个队列改进成一个环形队列
数组模拟环形队列
思路分析:
1.front:指向队列的第一个元素,也就是arr[front]就是队列的第一个元素,而不是arr[front-1]
2.Rear:指向队列的最后一个元素的后一个位置 ——为空出一个空间作为约定
3.当队列满时,条件为(rear + 1)%maxSize = front
4.当队列空时,条件为 rear == front
5.队列中有效数据的个数为(rear + maxSize - front) %maxSize
6.在原来的代码进行修改即可得到环形队列
代码实现
package Ivan.queue;
import java.util.Scanner;
public class CirceArrayQueueDemo {
public static void main(String[] args){
//测试。创建一个队列
CircleArray circleArray = new CircleArray(4);//设置说明是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': //显示数据
circleArray.showQueue();
break;
case 'a': //添加数据
try {
System.out.println("请输入一个数字");
int value = scanner.nextInt();
circleArray.addQueue(value);
}catch (Exception e){
System.out.println(e.getMessage());
}
break;
case 'g': //取出数据
try{
int res = circleArray.getQueue();
System.out.printf("取出的数据是%d\n",res);
}catch (Exception e){
System.out.println(e.getMessage());
}
break;
case 'h': //查看队列头部的数据e
try{
int res = circleArray.headQueue();
System.out.printf("队列头部数据是%d\n",res);
}catch (Exception e){
System.out.println(e.getMessage());
}
break;
case 'e': //退出命令
System.out.println("程序退出");
scanner.close();
loop = false;
break;
default:
break;
}
}
}
}
class CircleArray{
private int maxSize; //表示最大容量
private int front; //表示头指针,就指向队列第一个元素,初始值为0
private int rear; //表示尾指针,指向队列最后一个元素后一个位置,初始值也为0
private int[] arr; //用于存放数据,模拟队列
public CircleArray(int arrMaxSize){
maxSize = arrMaxSize;
rear = 0; //指向队列尾部后一个元素
front = 0; //指向队列头部的元素
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()){
throw new RuntimeException("队列已经满了");
}
arr[rear] = n;
//rear后移,但必须取模,防止数据溢出
rear = (rear + 1) % maxSize;
}
//获取队列的数据,出队列
public int getQueue(){
if (isEmpty()){
throw new RuntimeException("队列为空,没有数据");
}
int res = arr[front];
front++;
return res;
}
//求出当前队列有效值
public int size(){
return (rear - front + maxSize) %maxSize;
}
//显示队列的所有数据
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]);
}*/
//从front开始遍历
int sum = size();
for (int i = front; i < front + sum; i++) {
System.out.printf("arr[%d]%d\n",i%maxSize,arr[i%maxSize]);
}
}
//显示队列的头数据
public int headQueue(){
if (isEmpty()){
throw new RuntimeException("队列为空,没有数据");
}
return arr[front];
}
}