队列Queue
栈的实现原理为线性表,特点是只允许在线性表其中一端进行数据的增加操作,另一端进行删除操作,允许增加的一端为队尾(Tail/Rear),允许删除的一端称为队头(Head/Front)。
队列遵循先入先出的操作原则,即FIFO(First In First Out)。
队列的增加操作叫做入队,在队尾加入数据。
队列的删除操作叫做出队,在栈顶删除数据。
队列分为三种:普通队列()、双端队列、循环队列、优先级队列。
常用方法
| 返回值 | 方法 | 用途 |
|---|---|---|
| boolean | empty() | 判断栈是否为空 |
| E | peek() | 得到队头元素 |
| E | poll() | 将元素出队 |
| E | offer(E item) | 将元素入队 |
普通队列和双端队列
普通队列Queue:只允许在其中一端进行数据的增加操作,另一端进行删除操作。

双端队列Deque: 队头和队尾都可以进行数据的增加和删除操作。

普通队列和双端队列通常建议使用链表实现,增加和删除操作的时间复杂度为O(1)。
普通队列简单实现
class Node<E>{
public Object val;//数据
public Node next;
public Node(E val){
this.val=val;
}
}
public class MyQueue<E> {
private Node<E> head;//队头
private Node<E> last;//队尾
private int usedSize;//可用元素
/**
* 元素入队
* @param val
*/
public void offer(E val){
Node<E> node=new Node<>(val);
if(this.head==null){
this.head=node;
this.last=node;
}else {
this.last.next=node;
this.last=this.last.next;
}
this.usedSize++;
}
/**
* 判断队列是否为空
* @return
*/
public boolean empty(){
return this.head==null;
}
/**
* 元素出队
* @return
*/
public E poll(){
if(empty()){
throw new RuntimeException("队列为空");
}
Object oldValue=this.head.val;
this.head=this.head.next;
this.usedSize--;
return (E)oldValue;
}
public E peek(){
if(empty()){
throw new RuntimeException("队列为空");
}
return (E)this.head.val;
}
/**
* 队列中目前元素数量
* @return
*/
public int size(){
return this.usedSize;
}
}
循环队列
循环队列: 队头和队尾相接的顺序存储结构。

循环队列通常使用顺序表结构来存储数据,队头front和队尾rear相接来构成循环队列。
思路:设置两个标识front和rear代表队头下标和队尾下标,当队头或队尾走到顺表最后一个位置时,将队头或队尾重新指向队列开始开始时的下标来达到循环效果。
下标循环公式:(index+offset)%顺序表的长度array.length
index:队列结束位置
offset:队列最后一个位置到队头的偏移量
array.length:顺序表的长度
判断循环队列空与满
第一种方式:循环列表设置一个变量size用来表示当前队列内元素数量,当size为0,表示队列为空,当size等于队列长度,队列为满。
第二种方式:
1.设置一个标志位flag=false。
2.每次向队列放入一个元素时,flag置为true。
3.每次从队列放出一个元素时,flag置为false。
4.当rear 等于 front&&flag 为 false 时,队列为空;当rear 等于 front&&flag 为 true 时,队列为满;当 rear 不等于 front&&flag 为 false 时,队列有元素但是没有满。
第三种方式:
1.队列中保留一个位置不放元素。
2.每次存放元素之前先行检查 rear 下一个值是不是front,队列为满。
3.当 front 等于rear 队列为空。
循环队列简单实现
public class MyCircularQueue<E> {
private Object[] elem;
private int front;
private int rear;
public MyCircularQueue(int k) {
this.elem=new Object[k];
}
/**
* 元素入队
* @param value
* @return
*/
public boolean enQueue(E value) {
if(isFull()){
return false;
}
this.elem[rear]=value;
if(rear==this.elem.length-1){
rear=(rear+1)%this.elem.length;
}else {
rear++;
}
return true;
}
/**
* 元素出队
* @return
*/
public boolean deQueue() {
if(isEmpty()){
return false;
}
this.elem[front]=null;
if(front==this.elem.length-1){
front=(front+1)%this.elem.length;
}else {
this.front++;
}
return true;
}
/**
* 得到队头元素
* @return
*/
public E Front() {
if(isEmpty()){
throw new RuntimeException("队列为空");
}
return (E)this.elem[front];
}
/**
* 得到队尾元素
* @return
*/
public E Rear() {
if(isEmpty()){
throw new RuntimeException("队列为空");
}
int index=-1;
if(rear==0){
index=this.elem.length-1;
}else {
index=rear-1;
}
return (E)this.elem[index];
}
/**
* 判断队列是否为空
* @return
*/
public boolean isEmpty() {
return rear==front;
}
/**
* 判断队列是否为满
* @return
*/
public boolean isFull() {
return (rear+1)%this.elem.length==front;
}
}
本文详细介绍了队列的基本概念,包括其线性表的实现原理、FIFO操作原则以及普通队列、双端队列和循环队列的特性。通过实例展示了如何使用链表和顺序表实现队列,并探讨了队列的入队、出队、判断空满的操作。同时,提到了优先级队列这一高级应用。
1553

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



