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)

需要注意的是,所谓的【约定位置】对于数组来说是在不断变化的。不要通过数组下标来看这个环形队列,要通过头指针看其具体变化。

原文地址:https://www.cnblogs.com/zhao-xin/p/13108576.html