3、队列
基本介绍
- 队列是一个有序列表,可以用数组或是链表实现。
- 遵循先进先出的原则。
数组模拟队列
当我们将数据存入队列时称为”addQueue”,addQueue 的处理需要有两个步骤:
-
将尾指针往后移:rear+1 , 当front == rear 【空】
-
若尾指针 rear 小于队列的最大下标 maxSize-1,则将数据存入 rear所指的数组元素中,否则无法存入数据。 rear == maxSize - 1[队列满]
数组模拟队列代码实现
package com.atguigu.queue; import java.util.Scanner; public class ArrayQueueDemo { public void main(String[] args) { //测试 System.out.println("~~~环形队列的案例~~~"); // 初始化一个队列 ArrayQueue queue = new ArrayQueue(4); char key = ' '; boolean loop = true; Scanner scanner = new Scanner(System.in); 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': queue.showQueue(); break; case 'a': System.out.println("请输入一个数"); int value = scanner.nextInt(); queue.addQueue(value); break; case 'g': try { int res = queue.getQueue(); System.out.println("从队列中取出数据为" + res); } catch (Exception e) { // TODO: handle exception System.out.println(e.getMessage()); } break; case 'h': try { int res = queue.headQueue(); System.out.println("队列头元素值为=" + res); } catch (Exception e) { // TODO: handle exception System.out.println(e.getMessage()); } break; case 'e': scanner.close(); loop = false; default: break; } } } //使用数组模拟队列 编写一个ArrayQueue类 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; //指向队列的头部,front指向队列头的前一个位置 rear = -1; //指向队列尾,指向队列尾的数据(就是队列的最后一个数据) } //判断队列是否满 public boolean isFull(){ return rear == maxSize - 1; } //判断队列是否为空 public boolean isEmpty(){ return rear == front; } //添加数据到队列,入队列,从尾部插入 private void addQueue(int n){ //添加数据前先判断队列是否为满 if(isFull()){ System.out.println("队列已满,无法添加数据~~~~~"); return; } rear++; //队首指针不动,队尾指针后移 arr[rear] = n; } //获取队列的数据,出队列,从头部取出 public int getQueue(){ //判断队列是否为空 if(isEmpty()){ throw new RuntimeException("队列为空,不能读取数据~~~~~"); } front++; //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]; } } }
数据模拟环形队列
- 对front变量的含义做出调整:front指向队列的第一个元素,也就是个说arr[front]就是队列的第一个元素,front初始值为0 front=0.
- 对rear变量的含义做出调整:rear指向队列的最后一个元素的后面一个位置,因为希望空出一个空间作为约定(如果maxSize设置为4,那么队列的有效数据最多是3个),rear的初始值为0,rear=0.
- 队列满的条件是:(rear + 1) % maxSize == front
- 队列空的条件是:rear == front
- 分析后,队列中有效的数据的个数:(rear + maxSize - front) % maxSize
//最新版环形数组 package com.atguigu; import java.util.Scanner; public class CircleArrayQueueDemo { public static void main(String[] args) { System.out.println("~~~环形队列的案例~~~"); // 初始化一个队列 CircleArrayQueue queue = new CircleArrayQueue(4); char key = ' '; boolean loop = true; Scanner scanner = new Scanner(System.in); 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': queue.showQueue(); break; case 'a': System.out.println("请输入一个数"); int value = scanner.nextInt(); queue.addQueue(value); break; case 'g': try { int res = queue.getQueue(); System.out.println("从队列中取出数据为" + res); } catch (Exception e) { // TODO: handle exception System.out.println(e.getMessage()); } break; case 'h': try { int res = queue.headQueue(); System.out.println("队列头元素值为=" + res); } catch (Exception e) { // TODO: handle exception System.out.println(e.getMessage()); } break; case 'e': scanner.close(); loop = false; default: break; } } } } // 环形的队列和前面的单向队列有类似的地方,因为我们修改即可 class CircleArrayQueue { private int maxSize; private int[] arr; // 该数组存放数据,模拟队列 private int front; // 指向队列头部 private int rear; // 指向队列的尾部 public CircleArrayQueue(int arrMaxSize) { maxSize = arrMaxSize; arr = new int[maxSize]; } // 判断队列满的方法 // 队列容量空出一个作为约定 public boolean isFull() { // 1 => rear 1 // 2 => rear 2 // 3 => rear 3 return (rear + 1) % maxSize == front; } // 判断队列空的条件 public boolean isEmpty() { return rear == front; } // 添加数据到队列 public void addQueue(int n) { // 判断是否满 if (isFull()) { System.out.println("队列满,无法加入.."); return; } // 将数据加入 arr[rear] = n; // 然后将rear 后移, 这里必须考虑取模 rear = (rear + 1) % maxSize; } // 取出队列的数据(按先进先出的原则) public int getQueue() { 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 j = front; j < front + size(); j++) { System.out.printf("arr[%d]=%d\n", j % maxSize, arr[j % maxSize]); } } // 求出当前环形队列有几个元素 // 动脑筋 // 基础 【问题/需求 ---> 设计算法】 public int size() { // rear = 1 // front = 0 // maxSize = 3 return (rear + maxSize - front) % maxSize; } // 查看队列的头元素,但是不是改变队列 public int headQueue() { if (isEmpty()) { throw new RuntimeException("队列空~"); } // 这里注意,不要去改变fornt 值 return arr[front]; } }