Java Queue, Stack and Deque

Java Interface:

FIFO: Queue, Deque (not necessary) LIFO: Stack (do not use), Deque

deque和queue的关系,看Java Documentation, deque是queue的subinterface,所以deque实现了queue的功能。

Implementation Class:

Array: ArrayDeque Linked List: LinkedList Queue <> = new ArrayDeque

In Java

Queue

Java里的queue不一定是FIFO,例外是priority queue (heap)。所以其实in general, queue是一种数据结构,一头进,另一头出的基本功能。因为我们不希望random access, 所以arraylist就不合适了。

enqueue 入队: offer() at the tail dequeue 出队: poll() at the head peek 看第一个: peek() look at the head without polling it out

queue在空了的时候如果peek()和poll() 会拿出null. 下面表格的左右两组API不可以混用,必须consistent.

 Common APls  Queue  Type of  throw exception  return special  operation  value(null)  Insert  add(e)  offer (e) Remove  remove()  poll()  Examine  element()  peek ()\begin{array}{|l|l|l|}\hline & {\text { Common APls }} & {\text { Queue }} \\ \hline \text { Type of } & {\text { throw exception }} & {\text { return special }} \\ {\text { operation }} & {} & {\text { value(null) }} \\ \hline \text { Insert } & {\text { add(e) }} & {\text { offer }(e)} \\ \hline \text { Remove } & {\text { remove() }} & {\text { poll() }} \\ \hline \text { Examine } & {\text { element() }} & {\text { peek }()} \\ \hline\end{array}

在空了时如果调用remove()或者element(), NoSuchElementException; add(e)的异常是满了,比如用ArrayBlockingQueue就有容量限制,会throw IllegalStateException。如果是offer(),在满了时返回false,表示加失败了。

Deque

stack在空了的时候如果peek()和poll() 会拿出null,deque也是一样.

其他

isEmpty()

size()

stack method的Push Pop Peep 尽量不用

其实对应的是2个throw exception那组的addfirst removefirst 和 peekfirst 真是讨厌

Operation Cost O(1)

以上所有的实现,时间复杂度都是O(1) 常用LinkedList和ArrayDeque(Java6以后)实现。在实际使用中,更常用ArrayDeque,因为locality更低、overhead更好、出现null的时候没有歧义。而只有一个情况下需要使用linkedlist:版本是Java6之前的。

此外,ArrayDeque不允许null value,因为不能确定此时是值为null还是空了。这个时候如果用linkedlist实现就没有问题,因为list就可以存null(这里不是在说value是null)。

Implementation

arrayDeque和Linkedlist是用来实现stack queue 和deque这几个data structure的implementation class

Implement a Stack with Linked List

更好的是在头部插入删除,而不是在尾部。因为头部的操作更容易,而尾部即便是维护一个tail,每次在删除的时候就没了,又得再维护一个。

class ListNode{
    int value;
    ListNode next;
    public ListNode(int value){
    this.value=value;
    }
}

public class Stack{
    private ListNode head;
    
    Stack(){
    }
    
    public void push(int e){
    ListNode newhead = new ListNode(e);
    newhead.next=head;
    head=newhead;
    }
    
    public integer pop(){
    if (head==null){
        return null;                  //不要return head 不然类型不一致
    }
    ListNode prev=head;
    head = head.next;
    prev.next=null;                     //这里要防呆
    return head.value;
    }
    
    public integer peek(){
    if (head==null){
        return null;                  //不要return head 不然类型不一致
    }
    return head.value;
    }

}


//push()
//pop()
//peek()

Implement a Queue with Linked List

头进尾出:存在和上面一样的问题 尾进头出:和刚才一样

class ListNode{
    int value;           //如果允许存null value
    ListNode next;
    public ListNode(int value){
    this.value = value;
    }
}

public class QueueStack{
    private ListNode head;
    private ListNode tail;
    Queue(){
    }
    
    public void offer(int e){
    ListNode newtail = new ListNode(e);
    if (head == null){
        head = newtail;
        tail = head;
    }else{
        tail.next = newtail;
        tail = newtail;
    }
    
    public nteger poll(){
    if (head ==n ull){
        return null;                  
    }
    ListNode node = head;
    head = head.next;
    if (head == null){         //重要 只剩一个元素的时候head和tail是一个
        tail = null;
    }               
    node.next = null;    
    return node.value;
    }
    
    public nteger peek(){
    if (head == null){
        return null;                  
    }
    return head.value;
    }

}

Implement a Deque with Linked List

doubly linked list

Implement a Queue with Circular Array (Ring Buffer)

两种写法:

  • head = head +1==array.length?0: head+1;

  • head = (head+1)%array.length;

不要用这种写法,要防止overflow: head++; array[(head%array.length)]

head有数据,物理意义是next element in queue tail没数据,物理意义是next available position - poll: grab element at head, head++ - offer: put one element, tail++

当head==tail时,它要么是empty,要么满了,怎么知道是满了?解决方法:

  • 维护一个size 当size==0, empty; size==array.length, full

public class BoundedQueue {
    int head;
    int tail;
    int size;
    Integer[] array;
    
    public BoundedQueue(int cap) {
        array = new Integer[cap];
        head = tail = 0;
        size = 0
    }
    
    public boolean offer(Integer ele) {
    //1
        if (size == array.length){
            return false;
        }
    //2
        array[tail] = ele;
        tail = tail + 1 == array.length ? 0 : tail + 1;
        size ++;
        return true;
    }
    
    public Integer peek() {
        if (size == 0) {
            return null;
        }
        return array[head];
    }
    
    public int size() {
        return size;
    }
    
    public boolean isEmpty() {
        return size == 0;
    }
    
    public boolean isFull() {
        return size == array.length;
    }
}
  • 如果不支持加一个size,就改变head和tail的物理意义,使得head+1==tail时是空,而head==tail时是满,也就是head指的格子不存数据,tail的格子也不存数据。 - poll: grab element at head+1, head++ - offer:put one element, tail++

class Solution(object):

    def __init__(self, k):
        """
        Initialize your data structure here. Set the size of the queue to be k.
        :type k: int
        """
        self.array = [None]*(k+1)
        self.head = 0 #index of prev_to_the_next_available
        self.tail = 1 #index of the first available spot

    def enQueue(self, value):
        """
        Insert an element into the circular queue. Return true if the operation is successful.
        :type value: int
        :rtype: bool
        """
        if self.isFull():
          return False
        else:
          self.array[self.tail]=value
          self.tail=(self.tail+1)%len(self.array) 
          return True
        

    def deQueue(self):
        """
        Delete an element from the circular queue. Return true if the operation is successful.
        :rtype: bool
        """
        if self.isEmpty():
          return False
        else:
          self.head=(self.head+1)%len(self.array) 
          return True

        

    def Front(self):
        """
        Get the front item from the queue.
        :rtype: int
        """
        return -1 if self.isEmpty() else self.array[self.head+1]
        

    def Rear(self):
        """
        Get the last item from the queue.
        :rtype: int
        """
        return -1 if self.isEmpty() else self.array[(self.tail-1+len(self.array))%len(self.array)]
        

    def isEmpty(self):
        """
        Checks whether the circular queue is empty or not.
        :rtype: bool
        """
        return self.tail-self.head==1
        

    def isFull(self):
        """
        Checks whether the circular queue is full or not.
        :rtype: bool
        """
        return self.tail==self.head

如果满了,可以1.5X extension的话可以把数据从head拷贝到tail. 这里不是用system.copyof的方法,而是一个一个copy这些格子

Implement a Resizeable Stack with Circular Array

Implement a Resizeable Deque with Circular Array

Last updated