数据结构_用数组实现环形队列
思路分析:
一、front就指向队列的第一个元素,也就是说,arr[front]就是队列的第一个元素
二、rear就是指向队列的最后一个元素的后一个位置,我们需要空出这个rear指向的空间(牺牲这个空间)
三、现在环形队列中,当队列满时,条件为:( rear + 1 ) % maxSize == front
原本非环队列满的条件是 rear = maxSize - 1
我的解释是:
所以实际上这个环形队列实际的存储数据的长度(从0开始到x)为 maxSize - 2 ,也就是 这个空间的大小-1 ,剩下的这个空间被牺牲掉了,用来做判断这个环形队列是不是满的!
当然,上面的图从1开始是不严谨的,应该从0开始,从1开始只是我画的时候方便=-=
四、当队列为空的时候,条件仍然是 rear = front
五、队列中有效的数据的个数为( rear + maxSize - front ) % maxSize
这个公式的解释可以这样理解,首先rear加上maxSize也就是从数组的0位置开始到rear位置加上了容量大小,此时减去一个front就相当于数组中将这个占有数据的值往下推,推到从0位置到rear-front,
此时对maxSize取余就是相当于一个大于maxSize的数减去了一个maxSize所得到的余数,就是数组中有效存储的个数。
把这个公式这样写更好理解:
( rear - front + maxSize ) % maxSize
1、先不考虑这个环存取数据绕过一圈以上了,那么肯定有rear>front,那么rear-front就是存的有效个数
2、如果这个环存取数据也就rear和front通过一系列位移不知道是rear大还是front大
3、此时加上maxSize,就一定可以保证rear-front是一个正数,此时对maxSize取余可以得到有效个数了
代码部分:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 | package queue; import java.util.Scanner; public class CircleArrayQueueDEMO { public static void main(String[] args) { System.out.println( "测试——————————" ); System.out.println( "创建一个环形队列" ); CircleArrayQueue queue = new CircleArrayQueue( 3 ); char key = ' ' ; //接受用户输入的字符 Scanner sc = 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 = sc.next().charAt( 0 ); //接受输入的字符 switch (key) { case 's' : queue.ShowData(); break ; case 'a' : System.out.println( "输入一个数" ); int value = sc.nextInt(); queue.addQueue(value); break ; case 'g' : try { int res = queue.getQueue(); System.out.println( "数据是:" + res); } catch (Exception e) { System.out.println(e.getMessage()); } break ; case 'h' : try { int res = queue.headData(); System.out.println( "队列头数据是:" + res); } catch (Exception e) { System.out.println(e.getMessage()); } break ; case 'e' : sc.close(); loop = false ; break ; default : break ; } } System.out.println( "程序退出" ); } } class CircleArrayQueue { private int maxSize; //数组最大容量 private int front; //队列的头 arr[front]就是队列的头元素 private int rear; //指向队列最后一个元素的后一个位置(空间) arr[rear-1]就是队列的尾元素 private int [] arr; //队列中存放的数据,模拟队列 //队列的构造器 public CircleArrayQueue( int arrMaxSize) { maxSize = arrMaxSize+ 1 ; //加1是为了留给被牺牲的空间 arr = new int [maxSize]; } //判断队列是否满 public boolean isfull() { return (rear + 1 ) % maxSize == front; } //判断队列是否为空 public boolean isnull() { return rear == front; } //添加数据到队列 public void addQueue( int n) { //先判断是否为满 if (isfull()) { System.out.println( "队列满了,不能添加数据" ); return ; } arr[rear] = n; //上面判断了队列还没满, rear++; // 那么rear指向的位置就是空的,再后移 } //获取队列数据,取数据 public int getQueue() { //判断队列是否为空 if (isnull()) { //通过抛出异常 throw new RuntimeException( "队列空,不能取数据" ); } //front是指向队列的第一个元素 //一、先把front对应的值保留到一个临时变量(如果直接返回的return后面的代码不会执行) //二、将front后移 注意:front可能移到 maxSize-1 去了 //三、将临时保存的变量返回 int value = arr[front]; //任何数取余 它的余数不会超过除数 front = (front + 1 ) % maxSize; //取模是为了防止front越界,让到了maxSize-1就下去指向0 return value; } //显示队列所有的数据 public void ShowData() { if (isnull()) { System.out.println( "队列为空" ); } //从front开始遍历,遍历队列中有效的数据个数,从front -> rear,但rear可能小于front,因此要考虑取模 //队列中有效长度为queueLength int queueLength = (rear + maxSize - front) % maxSize; if (front < rear) { //front在rear下面 for ( int i = 0 ; i < queueLength; i++) { System.out.println( "队列第" + (i + 1 ) + "个元素为:" + arr[front + i]); } } else { //front在rear上面,(front+i)可能会越界 "任何数取余,它的余数不会超过除数" for ( int i = 0 ; i < queueLength; i++) { System.out.println( "队列第" + (i + 1 ) + "个元素为:" + arr[(front + i) % maxSize]); } } //不用上面的if的话,可以用下面的偷懒写法: // for (int i = front; i < front+size(); i++) { // System.out.println("arr["+ (i % maxSize) +"]="+ (arr[i%maxSize]) ); // } } public int size() { //计算循环队列中存储的个数 return (rear - front + maxSize) % maxSize; } //显示队列的头数据 不是取出 public int headData() { if (isnull()) { throw new RuntimeException( "队列是空的" ); } return arr[front]; } } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· Qt个人项目总结 —— MySQL数据库查询与断言