数据结构和算法003——队列(一般数组&&环形数组)
1、用数组模拟队列
先入先出FIFO
import java.util.Scanner; /** * @author yk * @create 2020/11/8 18:38 * 用数组模拟队列 * @description */ public class Test004 { public static void main(String[] args) { //测试 //创建一个队列 ArrayQueue queue = 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': 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.printf("取出的数是%d\n",res); } catch (Exception e) { System.out.println(e.getMessage()); } break; case 'h': try { int res = queue.peekQueue(); System.out.printf("队列头的数是%d\n",res); } catch (Exception e) { System.out.println(e.getMessage()); } break; case 'e': scanner.close(); loop = false; break; default: break; } } System.out.println("程序退出"); } } //用数组模拟队列,编写一个ArrayQueue类 class ArrayQueue { //表示数组的最大容量 private int maxSize; //指向队列的队列头 private int front; //指向队列的队列尾 private int rear; //该数组用于存放数据,模拟队列 private int[] arr; /** * 创建队列的构造器 * @param arrMaxSize */ public ArrayQueue(int arrMaxSize){ maxSize = arrMaxSize; arr = new int[maxSize]; //指向队列头部前面一个位置 front = -1; //指向队列尾部(即就是队列最后一个数据) rear = -1; } /** * 判断队列是否满 * @return */ public boolean isFull(){ return rear == maxSize - 1; } /** * 判断队列是否为空 * @return */ public boolean isEmpty(){ return rear == front; } /** * 添加数据到队列 * @param n */ public void addQueue(int n){ if (isFull()) { System.out.println("队列满,不能加入数据!"); return; } //让rear后移 rear++; arr[rear] = n; } /** * 获取队列数据(出队列),一个一个取 * @return */ public int getQueue(){ if (isEmpty()){ System.out.println("队列为空"); //通过抛出异常来处理 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]); } } /** * 获取队列头的数据 * @return */ public int peekQueue(){ if (isEmpty()){ throw new RuntimeException("队列为空,不能取数据"); } return arr[front + 1]; } }
2、环形队列
以上代码有个问题,数组只能使用一次,当队列满了后,一直调用getQueue()方法直到队列中没数据时,数据也加不进去了。
解决办法:将这个数组使用算法,改进成环形队列。
思路如下:
- front初始值为0;
- front变量含义做一个调整:front就指向队列的第一个元素,也就是arr[front]就是队列的第一个元素;
- rear变量含义做一个调整:rear就指向队列的最后一个元素的后一个位置,因为希望空出一个空间作为约定。
- 当队列满时,条件是(rear+1)%maxSize = front(理解下:如下图)
- 当队列为空时,rear = front
- 队列中有效数据的个数为:(rear + maxSize - front) % maxSize
rear | front | maxSize | 有几个值 |
1 | 0 | 3 | 1 |
7.改写代码
下图是满的时候,红表示front的指针,蓝表示rear的指针
下面表示队列为空时。
import java.util.Scanner; /** * @author yk * @create 2020/11/8 20:25 * 环形队列 * @description */ public class Test5 { public static void main(String[] args) { //测试 //创建一个队列 设置4,其队列的有效数据最大是3 CircleQueue queue = new CircleQueue(4); //接收用户的输入 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': 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.printf("取出的数是%d\n",res); } catch (Exception e) { System.out.println(e.getMessage()); } break; case 'h': try { int res = queue.peekQueue(); System.out.printf("队列头的数是%d\n",res); } catch (Exception e) { System.out.println(e.getMessage()); } break; case 'e': scanner.close(); loop = false; break; default: break; } } System.out.println("程序退出"); } } class CircleQueue { //表示数组的最大容量 private int maxSize; //front变量含义做一个调整:front就指向队列的第一个元素,也就是arr[front]就是队列的第一个元素;默认0 private int front; //rear变量含义做一个调整:rear就指向队列的最后一个元素的后一个位置,因为希望空出一个空间作为约定。默认0 private int rear; //该数组用于存放数据,模拟队列 private int[] arr; /** * 创建队列的构造器 * @param arrMaxSize */ public CircleQueue(int arrMaxSize){ maxSize = arrMaxSize; arr = new int[maxSize]; } /** * 判断队列是否满 * @return */ public boolean isFull(){ return (rear + 1) % maxSize == front; } /** * 判断队列是否为空 * @return */ public boolean isEmpty(){ return rear == front; } /** * 添加数据到队列 * @param n */ public void addQueue(int n){ if (isFull()) { System.out.println("队列满,不能加入数据!"); return; } //将数据放入,rear指针所在就是数据需要插入的地方 arr[rear] = n; //rear后移一位,这里需要考虑取模(在这里预留了一位空空间) rear = (rear + 1) % maxSize; } /** * 获取队列数据(出队列),一个一个取 * @return */ public int getQueue(){ if (isEmpty()){ System.out.println("队列为空"); //通过抛出异常来处理 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 < size(); i++) { System.out.printf("arr[%d]=%d\n",i % maxSize,arr[i % maxSize]); } } /** * 求出当前队列有效数据个数 * @return */ public int size(){ return (rear + maxSize - front) % maxSize; } /** * 获取队列头的数据 * @return */ public int peekQueue(){ if (isEmpty()){ throw new RuntimeException("队列为空,不能取数据"); } return arr[front]; } }