数组模拟队列与环形队列

本文最后更新于:2 年前

  • 队列是一个有序列表,可以用【数组】或【链表】来实现
  • 遵循先入先出的原则。即:先存入队列的数据,要先取出;后存入的要后取出

数组模拟队列

思路分析

  1. 示意图

    数组模拟队列示意图

    队列本身是有序列表,若使用数组的结构来存储队列的数据,则队列数组的声明如上图, 其中 maxSize 是该队列的最大容量。

    因为队列的输出、输入是分别从前后端来处理,因此需要两个变 frontrear分别记录队列前后端的下标,front 会随着数据输出而改变,而 rear则是随着数据输入而改变。

  2. 当我们将数据存入队列时称为 addQueue,需要两个步骤:

    1. 将尾指针往后移:rear+1 , 当front == rear 时,【队列空】
    2. 若尾指针 rear 小于队列的最大下标 maxSize-1,则将数据存入 rear 所指的数组元素中,否则无法存入数据。 rear == maxSize - 1 时,【队列满】

代码实现

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
public class ArrayQueue {

/**数组的最大容量**/
private int maxSize;
/**队列头**/
private int front;
/**队列尾**/
private int rear;
/**存放数据的数组, 模拟队列**/
private int[] arr;
/**记录队列的元素个数**/
private int length ;


/**
* 创建队列的构造器
* @param arrMaxSize
*/
public ArrayQueue(int arrMaxSize) {
//表示数组的最大容量
maxSize = arrMaxSize;
arr = new int[maxSize];
//指向队列头部,分析出front是指向队列头的前一个位置.
front = -1;
//指向队列尾,指向队列尾的数据(即就是队列最后一个数据)
rear = -1;
//队列初始化时没有元素
length = 0 ;
}


/**
* 判断队列是否满
*/
public boolean isFull() {
return rear == maxSize - 1;
}

/**
* 判断队列是否为空
*/
public boolean isEmpty() {
return rear == front;
}

/**
* 添加数据到队列
* @param n
*/
public void addQueue(int n) {
// 判断队列是否满
if (isFull()) {
System.out.println("队列已满,不能加入数据~");
return;
}
// 让rear后移
rear++;
arr[rear] = n;
length++;
}

/**
* 获取队列的数据, 出队列
* @return
*/
public int getQueue() {
// 判断队列是否空
if (isEmpty()) {
// 通过抛出异常
throw new RuntimeException("队列为空,不能取数据");
}
// front后移
front++;
length--;
return arr[front];

}

/**
* 显示队列的所有数据
*/
public void showQueue() {
// 遍历
if (isEmpty()) {
System.out.println("队列空的,没有数据~~");
return;
}
for (int i = 0; i < arr.length; i++) {
System.out.printf("arr[%d]=%d\n", i, arr[i]);
}
}

/**
* 显示队列的头数据, 注意不是取出数据
* @return
*/
public int headQueue() {
// 判断
if (isEmpty()) {
throw new RuntimeException("队列为空,没有数据~~");
}
return arr[front + 1];
}

public int queueLength(){
return length;
}
}

缺点分析:目前的队列只能使用一次就不能用了,没有达到复用的效果。


环形队列

对前面的数组模拟队列的优化,充分利用数组。因此将数组看做是一个环形的。(通过取模的方式来实现即可)。

思路分析

  1. 分析说明

    • 尾索引的下一个为头索引时表示队列满,即将队列容量空出一个作为约定。这个在做判断队列满的时候需要注意: (rear + 1) % maxSize == front时,队列满。
    • rear == front时, 【队列空】。
  2. 分析示意图:

环形队列思路分析图

代码实现

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
public class CircleArrayQueue {

//数组的最大容量
private int maxSize;
//front 变量的含义做一个调整:front 就指向队列的第一个元素,
//也就是说 arr[front] 就是队列的第一个元素,front的初始值 = 0
private int front;
//rear变量的含义做一个调整:rear指向队列的最后一个元素的后一个位置. 空出一个空间做为约定
//rear的初始值=0
private int rear;
//存放数据的数组, 模拟队列
private int[] arr;


/
public CircleArrayQueue(int arrMaxSize) {
maxSize = arrMaxSize;
arr = new int[maxSize];
}


/**
* 判断队列是否满
**/
public boolean isFull() {
return (rear + 1) % maxSize == front;
}

/**
* 判断队列是否为空
**/
public boolean isEmpty() {
return rear == front;
}

/**
* 添加数据到队列
**/
public void addQueue(int n) {
// 判断队列是否满
if (isFull()) {
System.out.println("队列满,不能加入数据~");
return;
}
//直接将数据加入
arr[rear] = n;
//将 rear 后移, 这里必须考虑取模
rear = (rear + 1) % maxSize;
}

/**
* 获取队列的数据, 出队列
**/
public int getQueue() {
// 判断队列是否空
if (isEmpty()) {
// 通过抛出异常
throw new RuntimeException("队列空,不能取数据");
}
// 这里需要分析出 front是指向队列的第一个元素
// 1. 先把 front 对应的值保留到一个临时变量
// 2. 将 front 后移, 考虑取模
// 3. 将临时保存的变量返回
int value = arr[front];
front = (front + 1) % maxSize;
return value;
}

/**
* 显示队列的所有数据
**/
public void showQueue() {
// 遍历
if (isEmpty()) {
System.out.println("队列空的,没有数据~~");
return;
}
// 思路:从front开始遍历,遍历多少个元素
// 动脑筋
for (int i = front; i < front + size(); i++) {
System.out.printf("arr[%d]=%d\n", i % maxSize, arr[i % maxSize]);
}
}

/**
* 求出当前队列有效数据的个数
**/
public int size() {
// rear = 2
// front = 1
// maxSize = 3
return (rear + maxSize - front) % maxSize;
}

/**
* 显示队列的头数据, 注意不是取出数据
**/
public int headQueue() {
// 判断
if (isEmpty()) {
throw new RuntimeException("队列空的,没有数据~~");
}
return arr[front];
}

}