簡體   English   中英

Java Queue 的最佳實現?

[英]Best implementation of Java Queue?

我正在(在 Java 中)研究遞歸圖像處理算法,該算法從中心點向外遞歸遍歷圖像的像素。

不幸的是,這會導致堆棧溢出。 所以我決定切換到基於隊列的算法。

現在,這一切都很好,但考慮到它的隊列將在很短的時間內分析數千個像素,同時不斷彈出和推送,而不保持可預測的狀態(它可能在長度 100,和 20000),隊列實現需要具有顯着快速的彈出和推送能力。

鏈表看起來很有吸引力,因為它能夠將元素推入自身而不重新排列列表中的任何其他內容,但為了使其足夠快,它需要輕松訪問其頭部和尾部(或第二個) -last 節點,如果它不是雙向鏈接的)。 遺憾的是,我找不到任何與 Java 中鏈表的底層實現相關的信息,所以很難說鏈表是否真的是要走的路......

這讓我想到了我的問題。 對於我打算做的事情,Java 中 Queue 接口的最佳實現是什么? (我不希望編輯甚至訪問隊列的頭部和尾部以外的任何東西——我不想做任何重新排列或任何事情。另一方面,我確實打算做很多推動並彈出,並且隊列的大小會發生很大變化,因此預分配效率低下)

采用:

Queue<Object> queue = new LinkedList<>();

JAVA 定義了接口QueueLinkedList提供了實現。

您可以使用.add(E e)將元素附加到隊列的末尾,並使用.remove()出列並檢索隊列的頭部(第一個元素)。

它還維護對 Head 和 Tail 元素的引用,您可以分別通過.getFirst().getLast()獲取.getFirst()


感謝@Snicolas 提出隊列接口的建議

如果您使用 LinkedList,請小心。 如果你像這樣使用它:

LinkedList<String> queue = new LinkedList<String>();

那么你可以違反隊列定義,因為可以刪除除第一個之外的其他元素(LinkedList中有這樣的方法)。

但是如果你像這樣使用它:

Queue<String> queue = new LinkedList<String>();

應該沒問題,因為這是提醒用戶,插入應該只發生在后面,刪除應該只發生在前面。

您可以通過將 LinkedList 類擴展到一個 PureQueue 類來克服 Queue 接口的有缺陷實現,該類拋出任何有問題的方法的 UnsupportedOperationException。 或者,您可以通過只創建一個字段類型為 LinkedList 對象列表的 PureQueue 來采用聚合方法,唯一的方法是默認構造函數、復制構造函數、 isEmpty()size()add(E element)remove()element() 所有這些方法都應該是單行的,例如:

/**
* Retrieves and removes the head of this queue.
* The worstTime(n) is constant and averageTime(n) is constant.
*
* @return the head of this queue.
* @throws NoSuchElementException if this queue is empty.
*/
public E remove()
{
    return list.removeFirst();
} // method remove()

查看Deque接口,它提供了兩端的插入/刪除。 LinkedList 實現了該接口(如上所述),但對於您的使用而言,ArrayDeque 可能更好——您不會產生為每個節點分配常量對象的成本。 再說一次,您使用哪種實現可能無關緊要。

正常多態性的好處開始發揮作用:針對 Deque 接口而不是它的任何特定實現編寫的美妙之處在於,您可以非常輕松地切換實現以測試哪個實現最好。 只需在其中使用new更改行,其余代碼保持不變。

在 Java 中實現 Stack 和 Queue 時,最好使用 ArrayDeque 而不是 LinkedList。 當用作堆棧時,ArrayDeque 可能比 Stack 接口更快(而 Stack 是線程安全的),當用作隊列時比 LinkedList 更快。 看看這個鏈接Use ArrayDeque 而不是 LinkedList 或 Stack

我認為您可以通過簡單的實現來解決問題

package DataStructures;

public class Queue<T> {

   private Node<T> root;

   public Queue(T value) {
      root = new Node<T>(value);
   }

   public void enque(T value) {
      Node<T> node = new Node<T>(value);
      node.setNext(root);
      root = node;
   }

   public Node<T> deque() {

      Node<T> node = root;
      Node<T> previous = null;

      while(node.next() != null) {
         previous = node;
         node = node.next();
      }
      node = previous.next();
      previous.setNext(null);
      return node;
   }

   static class Node<T> {

      private T value;
      private Node<T> next;

      public Node (T value) {
         this.value = value;
      }

      public void setValue(T value) {
         this.value = value;
      }

      public T getValue() {
         return value;
      }

      public void setNext(Node<T> next) {
         this.next = next;
      }

      public Node<T> next() {
         return next;
      }
   }
}

如果您知道隊列中可能的項目數量的上限,則循環緩沖區比 LinkedList 更快,因為 LinkedList 為隊列中的每個項目創建一個對象(鏈接)。

但是,如果您仍然想使用遞歸算法,則可以將其更改為“尾遞歸” ,這可能在 JVM 中進行了優化以避免堆棧溢出。

O(1) 訪問第一個和最后一個節點。

class Queue {

    private Node head;
    private Node end;

    public void enqueue(Integer data){

        Node node = new Node(data);
        if(this.end == null){
            this.head = node;
            this.end = this.head;
        }
        else {
            this.end.setNext(node);
            this.end = node;
        }
    }

    public void dequeue (){

        if (head == end){
            end = null;
        }

        head = this.head.getNext();
    }


    @Override
    public String toString() {
        return head.getData().toString();
    }

    public String deepToString() {

        StringBuilder res = new StringBuilder();
        res.append(head.getData());

        Node cur = head;
        while (null != (cur = cur.getNext())){
            res.append(" ");
            res.append(cur.getData());

        }
        return res.toString();
    }
}

class Node {

    private Node next;
    private Integer data;


    Node(Integer i){
        data = i;
    }

    public Integer getData() {
        return data;
    }

    public Node getNext() {
        return next;
    }

    public void setNext(Node next) {
        this.next = next;
    }
}

這是帶有IteratorIterable接口的隊列實現

隊列大小會隨着它變滿而增加

隊列接口

package com.practice.ds.queue;

import com.practice.ds.queue.exception.QueueException;

public interface QueueInterface<T> {

    public boolean empty();

    public void enqueue(T item);

    public void dequeue() throws QueueException;

    public T front() throws QueueException;

    public void clear();
}

自定義異常類

package com.practice.ds.queue.exception;

public class QueueException extends Exception {

    private static final long serialVersionUID = -884127093599336807L;

    public QueueException() {
        super();
    }

    public QueueException(String message) {
        super(message);
    }

    public QueueException(Throwable e) {
        super(e);
    }

    public QueueException(String message, Throwable e) {
        super(message, e);
    }
}

隊列的實現

package com.practice.ds.queue;

import java.util.Iterator;

import com.practice.ds.queue.exception.QueueException;

public class Queue<T> implements QueueInterface<T>, Iterable<T> {

    private static final int DEFAULT_CAPACITY = 10;
    private int current = 0;
    private int rear = 0;
    private T[] queueArray = null;
    private int capacity = 0;

    @SuppressWarnings("unchecked")
    public Queue() {
        capacity = DEFAULT_CAPACITY;
        queueArray = (T[]) new Object[DEFAULT_CAPACITY];
        rear = 0;
        current = 0;
    }

    @Override
    public boolean empty() {
        return capacity == current;
    }

    @Override
    public void enqueue(T item) {
        if(full())
            ensureCapacity();
        queueArray[current] = item;
        current++;
    }

    @Override
    public void dequeue() throws QueueException {
        T dequeuedItem = front();
        rear++;
        System.out.println("Dequed Item is " + dequeuedItem);
    }

    @Override
    public T front() throws QueueException {
        return queueArray[rear];
    }

    @Override
    public void clear() {
        for (int i = 0; i < capacity; i++)
            queueArray[i] = null;
        current = 0;
        rear = 0;
    }

    @SuppressWarnings("unchecked")
    private void ensureCapacity() {
        if (rear != 0) {
            copyElements(queueArray);
        } else {
            capacity *= 2;
            T[] tempQueueArray = (T[]) new Object[capacity];
            copyElements(tempQueueArray);
        }
        current -= rear;
        rear = 0;
    }

    private void copyElements(T[] array) {
        for (int i = rear; i < current; i++)
            array[i - rear] = queueArray[i];
        queueArray = array;
    }

    @Override
    public Iterator<T> iterator() {
        return new QueueItearator<T>();
    }

    public boolean full() {
        return current == capacity;
    }

    private class QueueItearator<T> implements Iterator<T> {

        private int index = rear;

        @Override
        public boolean hasNext() {
            return index < current;
        }

        @SuppressWarnings("unchecked")
        @Override
        public T next() {
            return (T) queueArray[index++];
        }
    }

}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM