一、基本介绍
1.概念
队列:(先进先出)队尾入队头出
只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出FIFO(First In First Out)
入队列:
进行插入操作的一端称为队尾(Tail/Rear)
出队列:
进行删除操作的一端称为队头(Head/Front)
2.队列是用什么实现的?
以下写的一般队列的底层是由双向链表实现的,数组实现太麻烦。循环队列使用的是数组实现的。
二、JAVA集合类对应的队列(LinkedList)
入队列:
linkedList.add();容量受限时会抛出异常
linkedList.offer();容量受限时return true比add()更好。
出队列:linkedList.poll() ;
得到队头元素:linkedList.peek();
public static void main(String[] args){
LinkedList<Integer> linkedList = new LinkedList<>();
//只要把握住 先进先出就好了
linkedList.add(1);
linkedList.offer(2);
linkedList.add(3);
System.out.println(linkedList.peek());//1
System.out.println(linkedList.poll());//1
System.out.println(linkedList.isEmpty());//
}
三、自己实现队列基本用法
1.初始化一个队列(链表)一定要定义头指针和尾指针
2.入队列,要考虑队列为空和只有一个链表的情况。
3.出队列,要考虑连表为空的情况
4.获得队列长度
class Node{
public int data;//数据域
public Node next;//指针
public Node(int data) {
this.data = data;
}
}
public class MyQueueLinked {
private Node front;//头指针
private Node rear;//尾指针
private int usedSize;//队列长度
/*
* 入队列
* @param val值
* */
public void offer(int val){
Node node=new Node(val);
if(this.front==null){
this.front=node;
this.rear=node;
}else{
this.rear.next=node;
this.rear=node;
}
this.usedSize++;
}
/**
* 出队头元素
* @return
*/
private boolean isEmpty() {
return this.usedSize==0;
}
public int poll(){
if(isEmpty()){
throw new RuntimeException(("队列为空"));
}
int val=this.front.data;
if(this.front.next==null){
//只有一个结点
this.front=null;
this.rear=null;
}else {
this.front = this.front.next;
}
this.usedSize--;
return val;
}
/**
* 得到队头元素 但是不删除
*/
public int peek(){
if(isEmpty()){
throw new RuntimeException(("队列为空"));
}
return this.front.data;
}
//获得队列长度
public int size(){
return this.usedSize;
}
public static void main1(String[] args) {
MyQueueLinked myQueueLinked = new MyQueueLinked();
myQueueLinked.offer(1);
myQueueLinked.offer(2);
myQueueLinked.offer(3);
System.out.println(myQueueLinked.peek());//1
System.out.println(myQueueLinked.poll());//1
System.out.println(myQueueLinked.peek());//2
System.out.println(myQueueLinked.poll());//2
System.out.println(myQueueLinked.isEmpty());//false
System.out.println(myQueueLinked.size());//
System.out.println(myQueueLinked.poll());//3
System.out.println(myQueueLinked.poll());//
}
}
四、循环队列基本操作
1.为什么要引入循环队列
由于一般队列的每个链表只能进行一次性的使用,为了更加节省内存,引入了循环队列,这里写的是用数组实现的循环队列。
2.基本操作
1.开辟循环队列空间
2.入队:从队尾开始入,入完以后,rear要多走到下一格。要考虑队满的情况,若是rear下一个元素为front则队已满,由于rear要多走到下一格,front前一个格子永远是空的。
3.出队:要考虑为空的情况,当rear=front时队列为空。
4.得到队头元素:考虑队列是否为空,返回front所在位置元素即可
5.得到队尾元素:考虑队列是否为空,和队尾元素为0的情况(队满的时候rear在front前一格的时候),此时返回队列长度-1的值。若在其他位置,则返回rear-1位置的元素,因为他每次入完一个元素,都会走到下一格。
代码中的(this.rear+1)%this.elem.length可以代表rear.next,意思是指针向前走一步
public class MyCircularQueue {
private int[]elem;//开辟空间
private int useSize;//实际长度
private int front;//头指针
private int rear;//尾指针
public MyCircularQueue(int k) {
this.elem = new int[k];
}
/**
* 入队
* @param value
* @return
*/
public boolean enQueue(int value) {
if (isFull()) {
return false;
}
this.elem[this.rear]=value;
this.rear=(this.rear+1)%this.elem.length;//rear向前走一步
return true;
}
public boolean isFull() {
if((this.rear+1)%this.elem.length==this.front){//rear.next的值等于front则满了
return true;
}
return false;
}
/**
* 出队
* @return
*/
public boolean deQueue(){
if(isEmpty()){
return false;
}
this.front=(this.front+1) % this.elem.length;//front向前走一步
return true;
}
public boolean isEmpty(){
if(this.rear==this.front){
return true;
}
return false;
}
/**
* 得到队头元素 相当于 peek()
* @return
*/
public int Front(){
if(isEmpty()){
return -1;//循环队列不可以抛异常
}
int val=this.elem[this.front];
return val;
}
/**
* 得到队尾元素
* @return
*/
public int rear(){
if(isEmpty()){
return -1;
}
if(this.rear==0){
return this.elem[this.elem.length-1];
}
return this.elem[this.rear-1];
}
}