Showing posts with label deque / double ended queue. Show all posts
Showing posts with label deque / double ended queue. Show all posts

Thursday, 7 July 2011

Deque in java

The java.util.Deque interface is a subtype of the java.util.Queue interface. It represents a queue where you can insert and remove elements from both ends of the queue. Thus, "Deque" is short for "Double Ended Queue" and is pronounced "deck", like a deck of cards.

Deque Implementations

Being a Queue subtype all methods in the Queue and Collection interfaces are also available in the Deque interface.

Since Deque is an interface you need to instantiate a concrete implementation of the interface in order to use it. You can choose between the following Deque implementations in the Java Collections API:


LinkedList is a pretty standard Deque / Queue implementation.

Internal Implementation
ArrayDeque stores its elements internally in an array. If the number of elements exceeds the space in the array, a new array is allocated, and all elements moved over. In other words, the ArrayDeque grows as needed, even if it stores its elements in an array.

Possible Usage
Because the double-ended queue supports addition or removal of elements from either end of the data structure, it can be used as a queue (first-in-first-out/FIFO) or as a stack (last-in-first-out/LIFO). J2SE 5 introduced a Queue interface and the Deque interface extends this interface. Note that a Vector-based Stack class has been present since JDK 1.0, but the Javadoc documentation for this class states that Deque should be used instead because it provides better LIFO operation support. Implementations of Deque are typically expected to perform better than Stack as well.

The Deque interface is extended by the concurrency-supporting interface BlockingDeque and is implemented by classes LinkedBlockingDeque (introduced in Java SE 6), LinkedList (available since JDK 1.2, but now implements Deque), and ArrayDeque (introduced in Java SE 6). For this blog entry, I will demonstrate using one Deque instance as a queue and one Deque instance as a stack using ArrayDeque for both. ArrayDeque is not thread-safe and does not allow for elements of the data structure to be null (a recommended but not required condition of Deque implementations and uses).

Operations on Deque
Adding to deque
To add elements to the tail of a Deque you call its add() method. You can also use the addFirst() and addLast() methods, which add elements to the head and tail of the deque.
Deque dequeA = new LinkedList();

dequeA.add ("element 1"); //add element at tail
dequeA.addFirst("element 2"); //add element at head
dequeA.addLast ("element 3"); //add element at tail

Getting or Peeking the element
You can peek at the element at the head of the queue without taking the element out of the queue. This is done via the element() method. You can also use the getFirst and getLast() methods, which return the first and last element in the Deque. Here is how that looks:
Object firstElement = dequeA.element();
Object firstElement = dequeA.getFirst();
Object lastElement = dequeA.getLast();

Removing the element
To remove elements from a deque, you call the remove(), removeFirst() and removeLast methods. Here are a few examples:
Object firstElement = dequeA.remove();
Object firstElement = dequeA.removeFirst();
Object lastElement = dequeA.removeLast();

Iterating over the elements
One method is normal foreach style:
//access via new for-loop
for(Object object : dequeA) {
String element = (String) object;
}

Another method is via iterator
//access via Iterator
Iterator iterator = dequeA.iterator();
while(iterator.hasNext(){
String element = (String) iterator.next();
}


Tuesday, 21 September 2010

ArrayDeque

ArrayDeque is an implementation of the 'Deque' interface i.e. java.util.ArrayDeque implements a double-ended queue, which allows efficient insertion and deletion at both ends. This an excellent choice for stacks and queues.
Double Ended Queue's extend 'Queue' and support adding and removing elements from both ends. In a Queue, you can add from one end and remove from the other. Also, Deque's can be used as a Queue and also a 'Stack'. ArrayDeque has no capacity restrictions like some other data structures (although you can specify that in one of its constructors). ArrayDeque is not threadsafe, as other collections like HashMap, et al. If you want it thread-safe, use 'LinkedBlockingQueue', which implements the 'BlockingQueue' interface, which further extends from 'Deque' interface.
An ArrayDeque has these characteristics:
  • Stack or queue. Supports operations to efficiently add, examine, or remove elements from either end.
  • Automatically expands as data is added to either the front or back. No capacity limit.
  • Good performance
    • Adding, examining, or deleting and element at either end of an ArrayDeque is O(1).
    • Generally faster than Stack.
    • Generally faster than LinkedList for queue operations.
  • Iteration - ArrayDeque implements Iterable, so can be traversed using a foreach loop or iterator. It also provides a descendingIterator() method for iterating in reverse order. So, a 'Deque' can be traversed from both directions programmatically using 'iterator' and 'descendingIterator' methods.
  • As with the other collections classes, only Object types are supported.
  • No indexed access is permitted.
  • No sorting is possible -- deques are not lists.
Deque vs LinkedList
 Deque is doubly linked and can be compared to 'LinkedList', which also implements a 'Deque', apart from List. In LinkedList, you can access an element randomly, by the element's index, which you cant do in Deque's. It was designed this way to make it more efficient.

Terminology

What are the ends called? The terminology of stacks and queues and lists is not standardized, so you'll see various terms for the ends.
  • Front = head = start = first.
  • Back = tail = end = last.

Common ArrayDeque methods and constructors

Here are some of the most useful ArrayDeque methods. Assume these declarations. Note that E is the notation for the type of an element in a collection.
int i;
boolean b;
ArrayDeque a;
E e;
Iterator iter;
E[] earray;
Object[] oarray;
ResultMethodDescription
Constructors
anew ArrayDeque()Creates ArrayDeque with initial default capacity.
anew ArrayDeque(cap)Creates ArrayDeque with initial int capacity cap.
anew ArrayDeque(coll)Creates ArrayDeque from the Collection coll.
Operations on the front (head, start, first)
a.addFront(e)adds e to the front of ArrayDeque a
b = a.offerFirst(e)Same as addFront. With capacity limited deques (not ArrayDeque) can return false.
e = a.getFirst()Returns, but does not remove, first element. Throws exception if deque is empty.
e = a.element()Same as getFirst.
e = a.peekFirst()Same as getFirst, but returns null if deque is empty.
e = a.peek()Same as peekFirst.
e = a.removeFirst()Returns and removes first element. Throws exception if deque is empty.
e = a.remove()Same as pollFirst.
e = a.pollFirst()Returns and removes first element. Returns null if deque is empty.
e = a.poll()Same as pollFirst.
e = a.pop()Same as removeFirst.
e = a.push(e)Same as addFront.
Operations on the back (tail, end, last)
a.addLast(e)adds e to the end of ArrayDeque a
a.add(e)Same as addLast.
b = a.offerLast(e)Same as addLast. With capacity limited deques (not ArrayDeque) can return false.
b = a.offer(e)Same as offerLast.
e = a.getLast()Returns, but does not remove, last element. Throws exception if deque is empty.
e = a.peekLast()Same as getLast, but returns null if deque is empty.
e = a.removeLast()Returns and removes last element. Throws exception if deque is empty.
e = a.pollLast()Returns and removes last element. Returns null if deque is empty.
Turning into an array
oarraya.toArray()Returns values in array of objects.
earraya.toArray(E[])The array parameter should be of the E class. Returns values in that array (or a larger array is allocated if necessary).
Iterators
itera.iterator()Returns an Iterator for forward traversal.
itera.descendingIterator()Returns an Iterator for backward traversal.
Searching
ba.contains(e)Returns true if ArrayDeque a contains e
ba.removeFirstOccurrence(e)Removes e from deque starting at beginning. Returns true if successful.
ba.removeLastOccurrence(e)Removes e from deque starting at end. Returns true if successful.
ba.remove(e)Same as removeFirstOccurrence().
Removing elements
Other
ia.size()Returns the number of elements in ArrayDeque a.
a.clear()removes all elements from ArrayDeque a

To get successive elements from an ArrayDeque - Several ways

Use either the foreach loop or an Iterator.
  1. foreach loop. This is fast and works for all kinds of lists, but is not entirely flexible (only sequential forward with no deletions, additions, or multiple references). This should be your first choice in programming. Works efficiently with both ArrayDeque and LinkedList.
    ArrayDeque a = new ArrayDeque();
    . . .
    for (String s : a) {
    System.out.println(s);
    }
  2. Iterator - Allows simple forward traversal. Can be used for the largest number of other kinds of data structures. This example uses an Iterator to print all elements (Strings) in an ArrayDeque. It uses hasNext(), which returns true if there are more elements, and next(), which returns the next element. Works with both ArrayDeque and LinkedList.
    for (Iterator iter = a.iterator(); iter.hasNext();  ) {
    System.out.println(iter.next());
    }
  3. ListIterator - Allows traversal of the ArrayDeque, but it is more general than a simple Iterator, allowing inserts and deletes (although both are very slow for an ArrayDeque). It also allows bidirectional traversal. Works efficiently with both ArrayDeque and LinkedList.

ArrayDeque example in java

package collection;

import java.util.ArrayDeque;
import java.util.Iterator;

public class ArrayDequeDemo
{
public static void main(String[] args)
{
ArrayDeque arrDeque = new ArrayDeque();

arrDeque.add("mercedes");
arrDeque.add("porsche");
arrDeque.add("audi");

for(Iterator iter = arrDeque.iterator();iter.hasNext();) {
System.out.println(iter.next());
}

System.out.println();

arrDeque.addLast("bmw");
arrDeque.add("PORSCHE");
arrDeque.addLast("Ferrari");

for(Iterator iter = arrDeque.iterator();iter.hasNext();) {
System.out.println(iter.next());
}

System.out.println();

for(Iterator descendingIter = arrDeque.descendingIterator();descendingIter.hasNext();) {
System.out.println(descendingIter.next());
}

System.out.println();
System.out.println("First Element : " + arrDeque.getFirst());
System.out.println("Last Element : " + arrDeque.getLast());
System.out.println("Contains \"porsche\" : " + arrDeque.contains("porsche"));

arrDeque.addFirst("porsche");

System.out.println();

for(Iterator iter = arrDeque.iterator();iter.hasNext();) {
System.out.println(iter.next());
}

arrDeque.removeLastOccurrence("porsche");

System.out.println();

for(Iterator iter = arrDeque.iterator();iter.hasNext();) {
System.out.println(iter.next());
}

arrDeque.removeFirstOccurrence("porsche");
System.out.println();

for(Iterator iter = arrDeque.iterator();iter.hasNext();) {
System.out.println(iter.next());
}

System.out.println();
System.out.println("Popped Element : " + arrDeque.pop());

arrDeque.push("porsche");
System.out.println();

for(Iterator iter = arrDeque.iterator();iter.hasNext();) {
System.out.println(iter.next());
}

System.out.println("\n Size of Array Deck : " + arrDeque.size());

System.out.println("\n Peek : " + arrDeque.peek());

System.out.println("\n Peek First : " + arrDeque.peekFirst());
System.out.println("\n Peek Last : " + arrDeque.peekLast());

System.out.println();

for(Iterator iter = arrDeque.iterator();iter.hasNext();) {
System.out.println(iter.next());
}

System.out.println("\n Poll First : " + arrDeque.pollFirst());
System.out.println("\n Poll Last : " + arrDeque.pollLast());

System.out.println();

for(Iterator iter = arrDeque.iterator();iter.hasNext();) {
System.out.println(iter.next());
}

System.out.println("\n Poll : " + arrDeque.poll());

System.out.println("\n Peek First : " + arrDeque.peekFirst());
System.out.println("\n Peek Last : " + arrDeque.peekLast());

arrDeque.offerFirst("porsche");
arrDeque.offerLast("what the heck?");

System.out.println();

for(Iterator iter = arrDeque.iterator();iter.hasNext();) {
System.out.println(iter.next());
}

System.out.println("\n Get First : " + arrDeque.getFirst());
System.out.println("\n Get Last : " + arrDeque.getLast());

System.out.println("\n Element : " + arrDeque.element());

Object[] objArray = arrDeque.toArray();
System.out.println("\n Object Array Size : " + objArray.length);

String[] strArray = (String[]) arrDeque.toArray(new String[0]);
System.out.println("\n String Array Size : " + strArray.length);

ArrayDeque arrDequeClone = arrDeque.clone();
System.out.println("Clone Size : " + arrDequeClone.size());

System.out.println("arrDeque == arrDequeClone : " + (arrDeque == arrDequeClone));

System.out.println("arrDeque.equals(arrDequeClone) : " + arrDeque.equals(arrDequeClone));
}
}

See Oracle/Sun's website for more on this.