数据结构之队列

目录

一、什么是队列Queue

二、Queue的一些方法

三、什么是双端队列Deque

四、Deque的一些方法

 五、队列Queue的实现

六、循环队列 


一、什么是队列Queue

1.队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出 FIFO(First In First Out)
2. 入队列:进行插入操作的一端称为 队尾( Tail/Rear
3. 出队列:进行删除操作的一端称为 队头 Head/Front

二、Queue的一些方法

错误处理抛出异常返回特殊值
入队列add(e)
offer(e)
出队列
remove()
poll()
队首元素
element()
peek()

我们通常喜欢用offer()、poll()和peek()这一组。 

1.add()和offer()的区别:
add():如果可以在不违反容量限制的情况下立即将指定的元素插入此队列,则在成功时返回true,如果当前没有可用空间,则抛IllegalStateException
offer():如果可以在不违反容量限制的情况下立即将指定元素插入此队列中。当使用容量受限队列时,这种方法通常比add更可取,因为add此时会抛出异常,而offer会返回false
2.remove()和poll()的区别:
remove():检索并删除此队列的头。此方法与poll的不同之处在于,如果此队列为空,它会引发异常;否则:返回此队列的头部元素
poll():检索并删除此队列的头,如果此队列为空,则返回null;否则:返回此队列的头部元素
3.element()和peek()的区别:
element():检索但不删除此队列的头。此方法与peek的不同之处在于,如果此队列为空,则会引发异常;否则:返回此队列的头部元素
peek():检索但不删除此队列的头,如果此队列为空,则返回null;否则:返回此队列的头部元素

三、什么是双端队列Deque

双端队列( deque )是指允许两端都可以进行入队和出队操作的队列, deque “double ended queue” 的简称。 那就说明元素可以从队头出队和入队,也可以从队尾出队和入队

四、Deque的一些方法

头部 / 尾部
头部元素(队首)
尾部元素(队尾)
错误处理
抛出异常
返回特殊值
抛出异常
返回特殊值
入队列
addFirst(e)
offerFirst(e)
addLast(e)
offerLast(e)
出队列
removeFirst()
pollFirst()
removeLast()
pollLast()
获取元素
getFirst()
peekFirst()
getLast()
peekLast()

注意:Deque这个接口它实现了Queue这个接口,因此也会有Queue的方法(offer()、add()默认从队尾入队,remove()、poll()默认删除队头元素)。

对于LinkedList来说,它不仅可以当做普通队列,可以当做双端队列,可以当做双向链表,也可以当做栈,我们来回忆一下这幅图:

 五、队列Queue的实现

队列也可以数组和链表的结构实现,使用链表的结构实现更优一些,因为如果使用数组的结构,出队列在数组头上出数据,效率会比较低,所以我们使用单链表来尝试实现它。
那么,如果是用单链表来实现它的话,哪边当队头,哪边当队尾呢?如图所示:

 所以我们在队尾处加上一个last指针指向最后一个结点,那么从队尾尾插法入队,时间复杂度为O(1),出队也是O(1)

 

class Node{
    public int val;
    public Node next;

    public Node(int val){
        this.val = val;
    }
}
public class MyQueue {
    public Node head;
    public Node last;

    public void offer(int val){
        Node node = new Node(val);
        if(this.head == null){
            head = node;
            last = node;
        }else{
            last.next = node;
            last = last.next;
        }
    }
    public int poll(){
        if(isEmpty()){
            throw new RuntimeException("队列为空!");
        }
        int oldValue = head.val;
        this.head = head.next;
        return oldValue;
    }
    public boolean isEmpty(){
        return this.head == null;
    }
    public int peek(){
        if(isEmpty()){
            throw new RuntimeException("队列为空!");
        }
        return head.val;
    }
}
public class TestDemo {
    public static void main(String[] args) {
        MyQueue queue = new MyQueue();
        queue.offer(1);
        queue.offer(2);
        queue.offer(3);
        System.out.println(queue.peek());
        System.out.println(queue.poll());
        System.out.println(queue.poll());
        System.out.println(queue.poll());
        System.out.println(queue.poll());
    }
}
编译并运行该代码,输出如下:

六、循环队列 

1.概念:为充分利用向量空间,克服假溢出现象的方法是:将向量空间想象为一个首尾相接的圆环,并称这种向量为循环向量。存储在其中的队列称为循环队列(Circular Queue)。循环队列是把顺序队列首尾相连,把存储队列元素的表从逻辑上看成一个环,成为循环队列
假溢出:系统作为队列用的存储区还没有满,但队列却发生了溢出,我们把这种现象称为"假溢出"

 2.数组下标循环的一些方法

(1)下标最后再往后(offset 小于 array.length): index = (index + offset) % array.length

 (2)下标最前再往前(offset 小于 array.length): index = (index + array.length - offset) % array.length,如:

 3.如何判断循环队列是否空和满?

(1)使用usedSize      比较usedSize和数组长度,确定是空还是满

(2)使用标志位    flag=false(初始位置标志为false),元素入队列时,每放一个元素就置为true;出队时,每出一个元素就置为false,如图所示:

 (3)保留一个空位置      每次放元素之前都先检查一下rear的下一个是不是front,如果是那么就是满的,如图所示:

 现在我们来看一条题:

 

代码实现如下:(我们在判断空和满时使用第三种方法)

class MyCircularQueue {

    public int[] elem;
    public int front;
    public int rear;

    public MyCircularQueue(int k) {
        this.elem = new int[k + 1];//由于我们要保留一个空位置,所以我们有3个空间时希望放3个元素时却只能放2个元素,因此我们要让k+1
    }
    
    public boolean enQueue(int value) {
        if(isFull()){
            return false;
        }

        this.elem[rear] = value;
        rear = (rear + 1) % elem.length;
        return true;
    }
    
    public boolean deQueue() {
        if(isEmpty()){
            return false;
        }
        front = (front + 1) % elem.length;
        return true;
    }
    
    public int Front() {
        if(isEmpty()){
            return -1;
        }
        return elem[front];
    }
    
    public int Rear() {
        if(isEmpty()){
            return -1;
        }
        int index = -1;
        if(rear == 0){
            index = elem.length - 1;
        }else{
            index = rear - 1;
        }
        return elem[index];
    }
    
    public boolean isEmpty() {
       return front == rear;
    }
    
    public boolean isFull() {
        if((rear + 1) % elem.length == front){
            return true;
        }
        return false;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值