队列(Queue)
- 概念
队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出FIFO(First In First Out)
入队列:进行插入操作的一端称为队尾(Tail/Rear)
出队列:进行删除操作的一端称为队头
2.链表队列:
队列也可以数组和链表的结构实现,使用链表的结构实现更优一些,因为如果使用数组的结构,出队列在数组头上 出数据,效率会比较低。
java实现时:当只有一个标识头节点时,无论哪一种方法插入或者删除,总有一个的操作的复杂度为O(n),因此可以定义俩个标识,head为头,tail为尾。
java实现:
class Node1 { //链表的节点
public int val; //数据域
public Node1 next; //地址域
public Node1(int val) { //构造方法
this.val = val;
}
}
class MyQueue {
public Node1 head; //表示头的位置
public Node1 tail; //表示尾的位置
//从队尾插入数据
public void offer(int val) {
Node1 node =new Node1(val);
if (head ==null){ //第一次插入时,head tail均指向同一个节点
head = node;
tail = node;
return;
}else{
//不是第一次插入 tail插入
tail.next = node;
tail = tail.next;
}
}
//弹出队头的数据
public int poll() {
if (head ==null){
throw new RuntimeException("队列为空,无法弹出!");
}
Node1 a=head; //记录head的当前值
if (head.next == null){ //只有一个节点
a =head;
head = null;
tail = null; //tail置空,使队列为空,否则tail一直指向head,无法回收
}else{
a =head;
head = head.next; //直接队头往后移,使要弹出的数据进行垃圾回收
}
return a.val;
}
//显示队头的数据
public int peek() {
if (head ==null){
throw new RuntimeException("队列为空,没有队头!");
}
return head.val;
}
//判断队列是否为空
public boolean isEmpty() {
return head ==null;
}
}
循环队列
3.环形队列通常使用数组实现。
class MyCircularQueue {
public int[] elem;
public int front;
public int rear;
/** Initialize your data structure here. Set the size of the queue to be k. */
public MyCircularQueue(int k) {
this.elem = new int[k+1];
}
/** Insert an element into the circular queue. Return true if the operation is successful. */
public boolean enQueue(int value) {
if (isFull()){
throw new RuntimeException("队满!");
}
elem[rear]=value;
rear =(rear+1)%elem.length;
return true;
}
/** Delete an element from the circular queue. Return true if the operation is successful. */
public boolean deQueue() {
if (isEmpty()){
throw new RuntimeException("队空!");
}
front =(front+1)%elem.length;
return true;
}
/** Get the front item from the queue. */
public int Front() {
if ( isEmpty()){
return -1;
}
return elem[front];
}
/** Get the last item from the queue. */
public int Rear() {
if ( isEmpty()){
return -1;
}
int index = rear == 0 ? elem.length-1 : rear-1;
return elem[index];
}
/** Checks whether the circular queue is empty or not. */
public boolean isEmpty() {
return front == rear;
}
/** Checks whether the circular queue is full or not. */
public boolean isFull() {
return front == (rear+1)%elem.length;
}
}
注意事项:
1.
循环队列在实现中的难点就是尾插数据时如何从数组的最后一个下标跳转到第0个下标,而最常见的办法就是:rear=(rear+1)%elem.length;即通过这个式子来表示每次的rear++;同理,也可以用front = (front+1)%elem.length来表示front++。
2.
当返回队尾元素时,当队尾为0时,如何跳转到前一个元素,即rear从头返回为尾,此时的做法为:rear == 0 ? elem.length-1 : rear-1,即一个if判断。
双端循环队列
与循环队列非常相似,即循环队列增加了头插,尾删,此时头插要考虑的是:
头插时,必然要将头的指示从当前位置-1,再插入数据,同样的面临的时从0到尾的烦恼,尾删也是一样,诚然用上述2的方法也可以(即用if语句判断特殊情况),但还有一种方法就是找到一个表达式,使从0到尾也能逆转:(rear-1+elem.length)%elem.length,此时双端循环队列也变得简单!
代码如下:
//双端循环队列
class MyCircularDeque {
public int[] elem;
public int front;
public int rear;
int len ;
public MyCircularDeque(int k) {
elem = new int[k+1]; //满足一部分题要求队列不占用一个空间来标识队满
len=elem.length;
}
/** Adds an item at the front of Deque. Return true if the operation is successful. */
public boolean insertFront(int value) {
if (!isFull()){
front=(front-1+len)%len;
elem[front]=value;
return true;
}
return false;
}
/** Adds an item at the rear of Deque. Return true if the operation is successful. */
public boolean insertLast(int value) {
if (!isFull()){
elem[rear]=value;
rear=(rear+1)%len;
return true;
}
return false;
}
/** Deletes an item from the front of Deque. Return true if the operation is successful. */
public boolean deleteFront() {
if (!isEmpty()){
front=(front+1)%len;
return true;
}
return false;
}
/** Deletes an item from the rear of Deque. Return true if the operation is successful. */
public boolean deleteLast() {
if (!isEmpty()){
rear=(rear-1+len)%len;
return true;
}
return false;
}
/** Get the front item from the deque. */
public int getFront() {
if (!isEmpty()){
return elem[front];
}
return -1;
}
/** Get the last item from the deque. */
public int getRear() {
if (!isEmpty()){
int index = rear == 0 ? len-1 : rear-1;
return elem[index];
//此时,就可以用直接的表达式来返回,例如:
//return (rear-1+len)%len;
}
return -1;
}
/** Checks whether the circular deque is empty or not. */
public boolean isEmpty() {
return front==rear;
}
/** Checks whether the circular deque is full or not. */
public boolean isFull() {
return front==(rear+1)%len;
}
}