基本定义:

  int[] arr 是定义一个整型数组当队列
  maxSize是数组的最大容量
  (这里规定,满队列时元素的个数是maxSize-1)
  front指向队列的第一个元素,也就是说 array[front] 是队列的第一个元素
  rear指向队列的最后一个元素,初值为0
  队列满的条件:(rear + 1) % maxSize == front
  队列为空的条件: rear == front

代码

  1. package com.zzfan.queue;
  2. import java.util.*;
  3. public class CircleArrayQueue {
  4. public static void main(String[] args) {
  5. System.out.println("测试数组环形队列");
  6. //创建一个环形队列
  7. CircleArray queue = new CircleArray(4); //队列有效数据最大是3
  8. char key = ' '; //接收用户输入
  9. Scanner scanner = new Scanner(System.in);
  10. boolean loop = true;
  11. //输出菜单
  12. while (loop) {
  13. System.out.println("s(show):显示队列");
  14. System.out.println("e(exit):退出程序");
  15. System.out.println("a(add):添加数据到队列");
  16. System.out.println("g(get):从队列取出数据");
  17. System.out.println("h(head):查看队列头的数据");
  18. //接收一个字符
  19. key = scanner.next().charAt(0);
  20. switch (key) {
  21. case 's':
  22. queue.showQueue();
  23. break;
  24. case 'a':
  25. System.out.println("输出一个数");
  26. int value = scanner.nextInt();
  27. queue.addQueue(value);
  28. break;
  29. case 'g':
  30. try {
  31. int result = queue.getQueue();
  32. System.out.printf("取出的数据是%d\n", result);
  33. } catch (Exception e) {
  34. System.out.println(e.getMessage());
  35. }
  36. break;
  37. case 'h':
  38. try {
  39. int result = queue.headQueue();
  40. System.out.printf("头部的数据是%d\n", result);
  41. } catch (Exception e) {
  42. System.out.println(e.getMessage());
  43. }
  44. break;
  45. case 'e':
  46. scanner.close();
  47. loop = false;
  48. break;
  49. default:
  50. break;
  51. }
  52. }
  53. System.out.println("程序退出");
  54. }
  55. }
  56. class CircleArray {
  57. //数组的最大容量
  58. private int maxSize;
  59. //front指向队列的第一个元素,也就是说arr[front]是队列的第一个元素
  60. private int front;
  61. //rear指向队列的最后一个元素的最后一个位置,初值为0
  62. private int rear;
  63. private int[] arr; //该数据用于存放数据,模拟队列
  64. public CircleArray(int arrMaxSize) {
  65. maxSize = arrMaxSize;
  66. arr = new int[maxSize];
  67. }
  68. //判断是否满
  69. public boolean isFull() {
  70. return (rear + 1) % maxSize == front;
  71. }
  72. //判断是否为空
  73. public boolean isEmpty() {
  74. return rear == front;
  75. }
  76. //添加数据到队列
  77. public void addQueue(int n) {
  78. //判断队列是否已满
  79. if (isFull()) {
  80. System.out.println("队列已满");
  81. return;
  82. }
  83. //直接将数据加入
  84. arr[rear] = n;
  85. //将rear后移,必须考虑取模
  86. rear = (rear + 1) % maxSize;
  87. /*
  88. 这里手算了一下,实际取模就是想办法当rear和队列最大容量相等时,在加1就重新取到rear=1
  89. 有个通俗易懂的例子:跑步套圈
  90. 有一个环形跑道,假设,将环形跑道分割成10份。
  91. front某时刻跑到第3格了,rear此时刻已经跑到第10格了。
  92. 那么rear继续往下跑的时候,会发现,跑的第“11格”(实际并不存在)其实就是第1格,是第二圈的第1格。
  93. */
  94. }
  95. //获取队列的中的数据
  96. public int getQueue() {
  97. //判断队列是否空
  98. if (isEmpty()) {
  99. //通过抛出异常来处理
  100. throw new RuntimeException("队列为空,无法取出数据");
  101. //throw可以直接return一个异常,不用再写return
  102. }
  103. //front指向队列的第一个元素
  104. /*
  105. 1. 先把front对应的值保留到一个临时变量中
  106. 2. front后移,考虑取模
  107. 3. 将临时保存的变量返回
  108. */
  109. int value = arr[front]; //先获取数据,front再后移
  110. front = (front + 1) % maxSize;
  111. return value;
  112. }
  113. //显示队列的所有数据
  114. public void showQueue() {
  115. //遍历数组
  116. if (isEmpty()) {
  117. System.out.println("队列为空,没有数据");
  118. return;
  119. }
  120. //从front开始遍历,对需要遍历元素的个数进行计算。
  121. for (int i = front; i < front + size(); i++) {
  122. System.out.printf("arr[%d] = %d\n", i % maxSize, arr[i % maxSize]);
  123. }
  124. }
  125. //有效数据的个数
  126. public int size() {
  127. return (rear + maxSize - front) % maxSize;
  128. /*添加数据变的是rear,取出数据变的是front,所以当在第一个位置插入数据时,rear=2,front=1。
  129. 所以,如果不考虑取模,那有效数据个数就是rear-front
  130. 考虑取模的话会出现一种情况,rear已经开始“跑第二圈”了,front还在“第一圈”
  131. */
  132. }
  133. //显示队列头
  134. public int headQueue() {
  135. //判断是否为空
  136. if (isEmpty()) {
  137. throw new RuntimeException("队列为空,没有数据");
  138. }
  139. return arr[front];
  140. }
  141. }