数据结构_用数组实现环形队列

思路分析:

一、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];
    }
 
}

  

 

 

 

 

 

  

 

posted @   Lee最好好好吃饭  阅读(258)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· Qt个人项目总结 —— MySQL数据库查询与断言
点击右上角即可分享
微信分享提示