3、队列-数组模拟环形队列
来源:https://www.bilibili.com/video/BV1B4411H76f?p=15
一、思路
1、环形队列的属性依然包括:队列的最大容量(maxSize),队列头指针(front),队列尾指针(rear),以及用来存放数据的数组(arr);
2、需要注意的是,在此不能通过【指针++】的形式给下标赋值,这里用取模的方式实现下标的计算;
3、通过取模的形式,那么头指针和尾指针的初始值不应该被定义为-1,这里两者的初始值为0;
4、这里同样需要判断队列为空还是队列满,如果在当前状态下,头指针和尾指针重叠不好判断到底是空还是满,因此给队列加了一个【约定位置】。假设队列的大小想设置为3,那么加入【约定位置】之后,用来模拟队列的数组arr的大小应该是4。在不取出数据的情况下,front=0,当添加完第3个数据时,尾指针所在的位置是下标3,其下一个位置就是下标0(环形),由此可以判断队列满;同理,添加完3个数据后,想要取出,依次取出3个数据后,头指针所在的位置是下标3,两者重叠,由此判断队列空。这样就可以区分开了。
二、实现
1、创建一个代表队列的类,并将队列头指针和尾指针初始化为0。用来模拟队列的数组arr的大小为队列的大小+1。此处默认要添加的数据为int类型
1 public class CircleArrayQueue { 2 private int maxSize;//队列大小 3 private int front;//头指针 4 private int rear;//尾指针 5 private int[] arr;//模拟队列的数组 6 7 //构造器 环形不能像以前一样 【尾指针++】 【头指针++】 通过取模的方式给两个指针赋值 8 //不能再用-1这个初值,于是给maxSize多加了一个【约定位置】,代替之前的-1位置。多出的不用于存值 9 public CircleArrayQueue(int maxSize) { 10 this.maxSize = maxSize + 1;//多出一个作为约定 11 this.front = 0;//便于取模 12 this.rear = 0;//便于取模 13 this.arr = new int[this.maxSize]; 14 } 15 }
2、在CircleArrayQueue类中增加一个向队列中添加数据的方法。由于只有队列不满时才可以添加,因此还要额外添加一个判断队列满的函数。
1 //判断队列满 尾指针处于【约定位置】时,下个是头指针,则满 2 public boolean isFull(){ 3 return (rear+1) % maxSize == front; 4 } 5 //添加数据 6 // 原:添加时rear++,加入数据 7 // 现:rear初始为0 添加数据后的新位置为(rear+1)% maxSize 8 //添加完最后一个,指针会指向【约定位置】 若中间没有取值,该【约定位置】的下一个位置对应的就是头指针的位置。下次添加就会判断为队列满 9 public void addData(int data){ 10 if(this.isFull()){ 11 System.out.println("队列已满,不能继续添加数据"); 12 }else { 13 arr[rear] = data; 14 rear =(rear+1) % maxSize; 15 } 16 }
3、在CircleArrayQueue类中增加一个展示队列数据的方法,测试一下增加数据的功能。由于只有当队列不为空时才能对数据进行展示,因此需要再添加一个判断队列空的方法。此外,展示数据这里用的是for循环,因此还添加了一个计算当前队列的有效数据个数的方法。
1 //判断队列空 尾指针处于【约定位置】时 头指针也处于【约定位置】 则空 2 public boolean isEmpty(){ 3 return rear == front; 4 } 5 6 //计算队列的有效数据个数 7 public int dataCount(){ 8 return (rear + maxSize - front) % maxSize; 9 } 10 public void showData(){ 11 if(isEmpty()){ 12 System.out.println("队列为空,不能展示数据"); 13 }else { 14 for (int i = front; i < front+dataCount();i++){ 15 System.out.printf("arr[%d]=%d ",i % maxSize,arr[i % maxSize]); 16 } 17 } 18 }
对增加数据的功能进行测试
1 public static void main(String[] args) { 2 int maxSize = 3; 3 CircleArrayQueue circleArrayQueue = new CircleArrayQueue(maxSize); 4 5 Scanner sc = new Scanner(System.in); 6 circleArrayQueue.showData(); 7 8 while (true){ 9 int value = sc.nextInt(); 10 circleArrayQueue.addData(value); 11 circleArrayQueue.showData(); 12 } 13 }
结果
队列为空,不能展示数据 1 arr[0]=1 2 arr[0]=1 arr[1]=2 3 arr[0]=1 arr[1]=2 arr[2]=3 4 队列已满,不能继续添加数据 arr[0]=1 arr[1]=2 arr[2]=3
4、在CircleArrayQueue类中增加一个出队列功能。同时展示当前的头指针。
1 public int removeData(){ 2 if(isEmpty()){ 3 throw new RuntimeException("队列为空,无法移除数据"); 4 }else{ 5 int val = arr[front]; 6 front = (front + 1) % maxSize; 7 return val; 8 } 9 } 10 11 //输出头指针对应的内容 12 public int headPoint(){ 13 if(this.isEmpty()){ 14 throw new RuntimeException("队列为空,无法寻找头指针"); 15 }else { 16 return arr[front]; 17 } 18 }
测试
1 public static void main(String[] args) { 2 int maxSize = 3; 3 CircleArrayQueue circleArrayQueue = new CircleArrayQueue(maxSize); 4 circleArrayQueue.addData(1); 5 circleArrayQueue.addData(2); 6 circleArrayQueue.addData(3); 7 8 int val = 0; 9 10 val = circleArrayQueue.removeData(); 11 System.out.println("移除的值为:"+val); 12 System.out.println("头指针对应的值为:"+ circleArrayQueue.headPoint()); 13 circleArrayQueue.showData(); 14 System.out.println(); 15 16 System.out.println("添加一个数据"); 17 18 circleArrayQueue.addData(4); 19 20 circleArrayQueue.showData(); 21 22 System.out.println(); 23 24 val = circleArrayQueue.removeData(); 25 System.out.println("移除的值为:"+val); 26 System.out.println("头指针对应的值为:"+ circleArrayQueue.headPoint()); 27 circleArrayQueue.showData(); 28 29 System.out.println(); 30 31 val = circleArrayQueue.removeData(); 32 System.out.println("移除的值为:"+val); 33 System.out.println("头指针对应的值为:"+ circleArrayQueue.headPoint()); 34 circleArrayQueue.showData(); 35 36 System.out.println(); 37 38 val = circleArrayQueue.removeData(); 39 System.out.println("移除的值为:"+val); 40 System.out.println("头指针对应的值为:"+ circleArrayQueue.headPoint()); 41 circleArrayQueue.showData(); 42 43 System.out.println(); 44 45 val = circleArrayQueue.removeData(); 46 System.out.println("移除的值为:"+val); 47 System.out.println("头指针对应的值为:"+ circleArrayQueue.headPoint()); 48 circleArrayQueue.showData(); 49 }
结果
移除的值为:1 头指针对应的值为:2 arr[1]=2 arr[2]=3 添加一个数据 arr[1]=2 arr[2]=3 arr[3]=4 移除的值为:2 头指针对应的值为:3 arr[2]=3 arr[3]=4 移除的值为:3 头指针对应的值为:4 arr[3]=4 移除的值为:4 Exception in thread "main" java.lang.RuntimeException: 队列为空,无法寻找头指针 at com.neuzhaoxin.queue.CircleArrayQueue.headPoint(CircleArrayQueue.java:69) at com.neuzhaoxin.queue.CircleArrayQueueTest.main(CircleArrayQueueTest.java:59)
需要注意的是,所谓的【约定位置】对于数组来说是在不断变化的。不要通过数组下标来看这个环形队列,要通过头指针看其具体变化。