当前位置:   article > 正文

JAVA简单实现循环队列_循环队列java实现

循环队列java实现

循环队列介绍

  • ”先进先出”(FIFO)的一种数据结构;
  • 空间循环使用(队尾队头成环),分别有”队头”和“队尾"两个指针。

循环队列实现

基本属性和构造方法

利用泛型数组作为底层数据结构实现循环队列,定义基本属性和构造方法。

注意:

  • 数组中采用牺牲一个空间来作为判空和判满的区别
  • 定义默认大小MAX_SIZE为11,即数组默认开辟11个空间,初始化队列容量为10
  • 区分队列的容量为(MAX_SIZE-1),和实现数组的长度为MAX_SIZE
  1. //利用泛型数组作为底层数据结构实现循环队列
  2. private T[] data;
  3. private static int MAX_SIZE = 11;
  4. //队头指针
  5. int front;
  6. //队尾指针
  7. int rear;
  8. //true为满 false为空
  9. boolean flag = false;
  10. public MyQueue(){
  11. data = (T[]) new Object[MAX_SIZE];
  12. front = rear = 0;
  13. }
  14. public MyQueue(int maxsize){
  15. this.MAX_SIZE = maxsize+1;
  16. data = (T[]) new Object[MAX_SIZE];
  17. front = rear = 0;
  18. }

循环队列指针的理解

MAX_SIZE为数组实际长度,不是队列实际长度或队列容量

入队(移动队尾指针): rear =  ( rear + 1 ) %  MAX_SIZE

出队(移动对头指针):front =  ( front + 1 ) %  MAX_SIZE

判满:front ==  ( rear + 1 ) %  MAX_SIZE

判空:front == rear

为了方便理解,以上是一个容量为4的循环队列的一次循环过程图。可以对着理解一下”队头”和“队尾"两个指针在这个过程中的计算变化。

基本方法实现

  1. //入队
  2. public void enqueue(T t) {
  3. if(front == (rear+1)%MAX_SIZE || flag){
  4. throw new RuntimeException("queue is full!!!!!!");
  5. }else {
  6. data[rear] = t;
  7. rear = (rear + 1) % MAX_SIZE;
  8. if (front == (rear+1)%MAX_SIZE) {
  9. flag = true;
  10. }
  11. }
  12. }
  13. //出队
  14. public T dequeue() {
  15. if(front == rear && !flag){
  16. throw new RuntimeException("queue is empty!!!!!!");
  17. }else {
  18. T element = data[front];
  19. front = (front + 1) % MAX_SIZE;
  20. if (front == rear) {
  21. flag = false;
  22. }
  23. return element;
  24. }
  25. }
  26. //返回队头元素
  27. public T peek(){
  28. if(front == rear && !flag){
  29. throw new RuntimeException("queue is empty!!!!!!");
  30. }else {
  31. return data[front];
  32. }
  33. }
  34. //判断队列是否为空
  35. public boolean isEmpty(){
  36. return !flag;
  37. }
  38. //返回队列容量
  39. public int capacity(){
  40. return MAX_SIZE-1;
  41. }
  42. //返回队列长度
  43. public int actualSize(){
  44. if(rear > front){
  45. return rear-front;
  46. } else if (rear < front){
  47. return MAX_SIZE - (front - rear);
  48. } else if (rear == front) {
  49. return 0;
  50. }
  51. return -1;
  52. }
  53. //tostring
  54. public String toString(){
  55. StringBuilder stringBuilder = new StringBuilder();
  56. stringBuilder.append("[");
  57. if(rear > front){
  58. for (int i = front; i < rear; i++) {
  59. stringBuilder.append(data[i]);
  60. if (i != rear - 1){
  61. stringBuilder.append(",");
  62. }
  63. }
  64. } else if (rear < front){
  65. for (int i = front; i < MAX_SIZE; i++) {
  66. stringBuilder.append(data[i]);
  67. if (i != MAX_SIZE - 1){
  68. stringBuilder.append(",");
  69. }
  70. }
  71. for (int i = 0; i < rear; i++) {
  72. stringBuilder.append(data[i]);
  73. if (i != rear - 1){
  74. stringBuilder.append(",");
  75. }
  76. }
  77. } else if (rear == front) {
  78. stringBuilder.append("null");
  79. }
  80. stringBuilder.append("]");
  81. return stringBuilder.toString();
  82. }

扩容方法的实现

思路就是改变MAX_SIZE的值,利用System.arraycopy方法把旧数组复制到新数组。

  1. public void ensureCapacity(int size) {
  2. if(size < MAX_SIZE-1){
  3. throw new RuntimeException("Size is less than MAX_SIZE!!!!!!");
  4. }else {
  5. int old = MAX_SIZE;
  6. MAX_SIZE = size+1;
  7. T[] oldElements = data;
  8. data = (T[]) new Object[MAX_SIZE];
  9. System.arraycopy(oldElements, 0, data, 0, old);
  10. System.out.println("queue is full, capacity is expanded to " + data.length);
  11. }
  12. }

作业

设计一个循环队列,用data[0..MaxSize-1]存放队列元素,用front和rear分别作为队头和队尾指针,另外用一个标志tag标识队列可能空(false)或可能满(true),这样加上front==rear可以作为队空或队满的条件。要求设计队列的相关基本运算算法。

  1. package queue;
  2. import org.junit.jupiter.api.BeforeEach;
  3. import org.junit.jupiter.api.DisplayName;
  4. import org.junit.jupiter.api.Test;
  5. public class WorkTwoTest {
  6. MyQueue<Character> mq;
  7. @BeforeEach
  8. @DisplayName("入队测试")
  9. void init(){
  10. System.out.println("Test begin.......");
  11. mq = new MyQueue<>();
  12. mq.enqueue('a');
  13. mq.enqueue('b');
  14. mq.enqueue('c');
  15. mq.enqueue('d');
  16. }
  17. @Test
  18. @DisplayName("出队测试")
  19. void dequeueTest() {
  20. System.out.println("出队前:"+mq);
  21. System.out.println(mq.dequeue()+"已出队!");
  22. System.out.println("出队后:"+mq);
  23. System.out.println("========================");
  24. }
  25. @Test
  26. @DisplayName("扩容+返回队列长度测试")
  27. void ensureCapacityTest() {
  28. System.out.println("队列容量为:" + mq.capacity());
  29. System.out.println("队列实际长度为:" + mq.actualSize());
  30. mq.ensureCapacity(20);
  31. System.out.println("队列容量为:" + mq.capacity());
  32. System.out.println("========================");
  33. }
  34. @Test
  35. @DisplayName("返回队头元素测试")
  36. void peekTest() {
  37. System.out.println("队头元素为:"+mq.peek());
  38. System.out.println("========================");
  39. }
  40. }

测试结果如下

总结

根据循环队列的思想,可以学到:

  • 循环地使用空间可以减少空间的占用。
  • 想要获得循环的一组数可以参考循环队列指针的计算方法,用取模%运算得到。
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/神奇cpp/article/detail/867343
推荐阅读
相关标签
  

闽ICP备14008679号