私は(Javaで)画像のピクセルを中心点から外側に再帰的に走査する再帰的な画像処理アルゴリズムに取り組んでいます。
残念ながら、それはスタックオーバーフローを引き起こします。そこで、キューベースのアルゴリズムに切り替えることにしました。
さて、これはすべてうまくいきましたが、キューが非常に短い時間で数千のピクセルを分析し、常にポップおよびプッシュしながら、予測可能な状態を維持することなく、および20000)、キューの実装には、非常に高速なポップおよびプッシュ機能が必要です。
リンクされたリストは、リスト内の他の要素を再配置せずに要素を自分自身にプッシュできるため魅力的ですが、十分に速くするために、その頭とその尾(または2番目の-二重リンクされていない場合、最後のノード)。悲しいことに、Javaでのリンクリストの基礎となる実装に関連する情報を見つけることができないので、リンクリストが実際に進むべき方法であると言うのは難しいです...
これは私の質問に私をもたらします。 Java私がやろうとしていることに対するQueueインターフェースの最適な実装は何でしょうか?(キューの先頭と末尾以外を編集したり、アクセスしたくはありません-並べ替えなどをしたくありません。逆に、プッシュとポップをたくさん行うつもりで、キューのサイズがかなり変わるため、事前割り当ては非効率的です)
LinkedList は進むべき道のようです。LinkedListは二重にリンクされたリストで、Queueデータ構造(FIFO)に適しています。
.getFirst()
および.getLast()
でそれぞれ取得できるHeadおよびTail要素への参照を保持します。
.Push(E e)
を使用してキューの最後に要素を追加し、.pop()
を使用してキューの最後の要素をデキューおよび取得することもできます。
LinkedListを使用する場合は注意してください。このように使用する場合:
LinkedList<String> queue = new LinkedList<String>();
次に、キュー定義に違反する可能性があります。これは、最初以外の要素を削除できるためです(LinkedListにはそのようなメソッドがあります)。
ただし、次のように使用する場合:
Queue<String> queue = new LinkedList<String>();
これは、挿入は背面でのみ、削除は前面でのみ行う必要があることをユーザーに知らせるため、大丈夫です。
LinkedListクラスを問題のあるメソッドのUnsupportedOperationExceptionをスローするPureQueueクラスに拡張することにより、Queueインターフェースの実装の欠陥を克服できます。または、LinkedListオブジェクト、リストタイプのフィールドを1つだけ使用して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インターフェースに対する特定の実装ではなく、Dequeインターフェースに対する記述の美しさは、実装を切り替えて、どれが最高のパフォーマンスを発揮するかをテストできることです。 new
を含む行を変更するだけで、残りのコードは同じままです。
JavaでStackとQueueを実装するときは、LinkedListではなくArrayDequeを使用することをお勧めします。 ArrayDequeは、スタックとして使用する場合はStackインターフェイスよりも高速であり(Stackはスレッドセーフですが)、キューとして使用する場合はLinkedListよりも高速です。このリンクをご覧ください LinkedListまたはStackの代わりにArrayDequeを使用 。
キュー内の可能なアイテムの量の上限がわかっている場合、LinkedListはキュー内の各アイテムに対してオブジェクト(リンク)を作成するため、循環バッファーはLinkedListよりも高速です。
ただし、再帰アルゴリズムを引き続き使用する場合は、 "tail-recursive" に変更できます。これはおそらくスタックオーバーフローを回避するためにJVMで最適化されます。
最初と最後のノードへのO(1)アクセス。
クラス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();
}
}
クラス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;
}
}
実装のような単純なものでいくつかできると思います
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;
}
}
}
Queue実装IteratorおよびIterableインターフェース
キューサイズはいっぱいになると増加します
キューインターフェイス
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++];
}
}
}