队列
- 队列是一种特殊的线性表,特殊之处在于它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作,和栈一样,队列是一种操作受限制的线性表。进行插入操作的端称为队尾,进行删除操作的端称为队头。
顺序队列
-
建立顺序队列结构必须为其静态分配或动态申请一片连续的存储空间,并设置两个指针进行管理。一个是队头指针front,它指向队头元素;另一个是队尾指针rear,它指向下一个入队元素的存储位置。
-
顺序队列会存在存储空间的浪费,因为无论是头指针还是尾指针,他们都只能不断向后移动,这样随着入队出队操作的不断进行,前面的空间就会闲置下来,没法被利用。
-
顺序队列中的溢出现象:
- 下溢现象:当队列为空时,做出队运算产生的溢出现象。“下溢”是正常现象,常用作程序控制转移的条件。
- 真上溢现象:当队列满时,做进栈运算产生空间溢出的现象。“真上溢”是一种出错状态,应设法避免。
- 假上溢现象:由于入队和出队操作中,头尾指针只增加不减小,致使被删元素的空间永远无法重新利用。当队列中实际的元素个数远远小于向量空间的规模时,也可能由于尾指针已超越向量空间的上界而不能做入队操作。该现象称为"假上溢"现象。
代码实现
- 头指针
front
的作用是:指向队首的第一个元素。 - 尾指针
rear
的作用为:指向队尾最后一个元素的下一个位置 - 根据上面的定义,可以得到顺序队列的几种特殊状态:
- 队列空:front = rear
- 队列满:rear = array.length(array.length指代队列空间的长度)
- 则顺序队列的java实现为:
package 数据结构;
public class Queue1 {
private int front = 0;
private int rear = 0;
private final int[] queue;
// 构造函数
public Queue1(int size) {
queue = new int[size];
}
// 入队列
public boolean push_back(int value) {
if (rear == queue.length) return false;
else queue[rear++] = value;
return true;
}
// 出队列
public int pop_front() {
if (front == rear) System.out.println("队列空,出队列错误");
else return queue[front++];
return -1;
}
}
循环队列
- 顺序队列存在存储空间浪费的问题,为了解决这个问题,让数组空间循环利用起来。可以采用循环队列。
- 循环队列的基本思路就是收尾相连,循环利用;每当首/尾指针指向数组的最后一个单位空间的下一个空间时(溢出),就让它重新指向数组的第一个元素。
- 具体来说,可以用取余运算来达到这个要求,指针移动的表达式可以表示为(n为队列长度):
head = (head + 1) % n
tail = (tail + 1) % n
代码实现
- 头指针可定义为指向队首的第一个元素。
- 尾指针可定义为指向队尾最后一个元素的下一个位置。
- 则队列的几个特殊状态可以表示为:
- 队列空:
head = tail
; - 队列满:
head = (tail + 1) % n
;即队尾指针的下一个位置就是队首,由于尾指针指向的位置总是没有元素的,所以这里实际会有一个空间的浪费,但这可以帮助我们区分队列空和队列满,是有必要的。
- 队列空:
- 则循环队列的
java
实现为:
package 数据结构;
public class Queue {
private int head = 0;
private int tail = 0;
private final int[] queue;
// 构造函数
public Queue(int size) {
queue = new int[size];
}
// 向队尾添加元素
public boolean push_back(int value) {
if (head == (tail + 1) % queue.length) return false; // 队列满
queue[tail] = value;
tail = (tail + 1) % queue.length;
return true;
}
// 取队首元素
public int pop_head() {
if (head == tail) throw new Error("队列空"); // 队列空
int value = queue[head];
head = (head + 1) % queue.length;
return value;
}
// 获取队列中的元素数量
public int getElementNumber() {
if (head > tail) return tail + queue.length - head;
else return tail - head;
// 上面的两个可以合并为:
// (tail + queue.length - head) % queue.length
}
// 判空
public boolean isEmpty() {return head == tail;}
// 判满
public boolean isFull() {return head == (tail + 1) % queue.length;}
}