目录
1.数组队列的基本概念
2.代码实现
3.数组队列的不足
4.循环队列的基本概念
5.代码实现
6.总结
一.数组队列的基本概念
队列是一种线性的数据结构,其特点是先进先出;像排着一条队伍进房间,先排队则优先进入房间,想要排队必须从队尾开始排。
如图所示:

二.数组队列的代码实现
根据这个特点,以数组为存储容器,来模拟数组队列。
1.首先要确定队列大小(数组大小),设置最大容量:int MaxSize;
2.接着要实现队列的功能,需要设置两个变量来记录对头和队尾的下标;
int front = -1; //记录队头的下表
int rear = -1; //记录队尾的下表
3.队列有三种情况
(1) 当队列中没元素时我们规定第一个元素的前一个是front。
并且 front == rear ;
(2) 当队列满时最后一个元素的前一个为rear。
即 rear == MaxSize - 1;
所以判断队列是否满和空的代码如下:
//判断队列是否满
public boolean isFull(){
return rear==maxSize-1;
}
//判断队列是否空
public boolean isEmpty(){
return rear==front;
}
队列为空的情况: 队列满的情况:


只要rear == front ,队列便是空的,不一定要如上图。
特别说明:因为队列满时满足:rear = MaxSize -1; 而不管front处于什么位置,所以普通队列存在一个问题,数组队列只能用一次,当队列满后便无法复用。
(3)队列有空间且不为空时。
我们有两种功能,往队列中存数据,从队列中取数据。
存数组:从队尾加入一个数,并且队尾标志rear向后移动一位:rear++;
取数据:从对头取出一个数,并且对头标志front向后移动一位:front++;
//进对列存数据
public void addArr(char n){
if (isFull()){
System.out.println("队列满不能加入数据");
return;
}
rear++;
arr[rear] = n;
}
//获取队列的数据,出队列
public char getQueue(){
if (isEmpty()){
throw new RuntimeException("数组为空,不能取数据");
}
front++;
return arr[front];
}
进队如图:



注意:是先进行rear++,再让数据进队arr[rear] = value,所以当判满时条件仍然是: rear == MaxSize - 1;
出队如图:



只要出队一次,便front++,同样是是先进行front++,再让数据出队arr[front] = value;
4.其他的一些功能的代码。
打印数组队列,便按照数组规则遍历;取头元素,便通过arr[front+1]来看,注意是只查看不取出来。
//打印队列中的数据
public void showQueue(){
if (isEmpty()){
System.out.println("队列空没有数据");
return;
}
for (int i = 0; i < arr.length; i++) {
System.out.printf("arr[%d]=%c\n",i,arr[i]);
}
}
//显示头数据
public char headQueue(){
if (isEmpty()){
System.out.println("队列空没有数据");
}
return arr[front+1];
}
三.数组队列的局限和不足
上述特别说明中提到,当队列存满,便再也不能存数据。因此数组队列是一个一次性的存储结构。
因此引出一个优化的列表形式:循环列表。
四.循环队列的基本概念
1.首先,循环队列是只将队列首尾相接像一个环(实际上是通过取模的方式,让front和rear小于maxSize);但同样遵循先进先出,从队尾进队,从对头出队的原则
2.其次我们规定需要的变量:
确定循环队列容量:int maxSize;
空时队首:int front = 0; 队尾:rear= 0 //这次front代表头元素的数组下标。
满时队尾:int rear = maxSize +1 //rear代表最后一个元素的后一位,所以有一个空位
如图:

五.循环队列代码实现
1.判断队列空和满
队列依旧是数组队列,但实现循环,是通过对取模的方式防止数组越界,这样即使队列满了,只要出队取数据又可以存新的数据。
//判断队列是否满
public boolean isFull(){
return (rear+1)%maxSize==front;
}
//判断队列是否为空
public boolean isEmpty(){
return rear==front;
}
2.往队列存数据



下一次再存会先判断队列是否满,条件是 (rear+1)%maxSize == front;因此如图,当rear==6时队列已经满了,所以循环队列会预留一个空间。
代码如下:
取模操作同样是为了防止数组越界。
//添加数据到队列
public void addQueue(char n){
if (isFull()){
System.out.println("队列满,不能加入数据");
return;
}
//将要添加的数据存入队列数组
arr[rear] = n;
//将rear后移,这里必须考虑取模
rear = (rear + 1)%maxSize;
}
4.出队取数据


代码如下
//获取队列数据,出队列
public char getQueue(){
if (isEmpty()){
throw new RuntimeException("队列空,不能取数据");
}
//front移动位置,要做取模处理,防止数组越界
//1.先把front指向队列的第一个元素
//2.将front对应的值保留到一个临时变量
//3.将临时保存的变量返回
int value = arr[front];
front = (front + 1)%maxSize;
return value;
}
看看此时循环队列的优势出现了,现在再判断队列,此时(rear+1)%maxSize != front,所以可以接着存数据,直到再次满为止。

3.其他功能代码:
因为是循环队列,所以遍历从对头开始,遍历条件是front + 队列中存储数据的个数。
即front + (rear+maxSize-front)%maxSize;
//打印队列所以数据
public void showQueue(){
if (isEmpty()){
System.out.println("队列为空,没有数据");
return;
}
//从队首开始
for (int i = front; i < front+size(); i++) {
//因为是循环数组,下标要考虑取模
System.out.printf("arr[%d]=%c\n",(i%maxSize),arr[i%maxSize]);
}
}
//获取队列有效数值长度
public int size() {
return (rear+maxSize-front)%maxSize;
}
//显示队列的头元素
public int headQueue(){
if (isEmpty()){
System.out.println("队列空没有数据");
}
return arr[front];
}
六.总结
首先要明确队列的特点,先进先出,对头出队,队尾进队。其次通过数组对列探究对列的特性中设置了许多表示下标的变量,通过移动变量位置来实现入队出队;但实际上数组的值还是存在,只不过获取数据是通过arr[front]来获取。
在研究普通数组队列时我们发现一旦队列满就再也无法存储数据的问题,因此出现了循环队列,通过取模来防止数组越界以此重复利用数组,只要出队取数据,保证数组队列中有空间,便可再次存数据,因此解决了这个问题。
4668

被折叠的 条评论
为什么被折叠?



