Java Tutorial/Collections/Queue

Материал из Java эксперт
Перейти к: навигация, поиск

A Priority Queue

/**
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/** A PriorityQueue maintains a partial ordering of its elements such that the
  least element can always be found in constant time.  Put()"s and pop()"s
  require log(size) time. */
public abstract class PriorityQueue {
  private Object[] heap;
  private int size;
  private int maxSize;
  /** Determines the ordering of objects in this priority queue.  Subclasses
      must define this one method. */
  protected abstract boolean lessThan(Object a, Object b);
  /** Subclass constructors must call this. */
  protected final void initialize(int maxSize) {
    size = 0;
    int heapSize = maxSize + 1;
    heap = new Object[heapSize];
    this.maxSize = maxSize;
  }
  /**
   * Adds an Object to a PriorityQueue in log(size) time.
   * If one tries to add more objects than maxSize from initialize
   * a RuntimeException (ArrayIndexOutOfBound) is thrown.
   */
  public final void put(Object element) {
    size++;
    heap[size] = element;
    upHeap();
  }
  /**
   * Adds element to the PriorityQueue in log(size) time if either
   * the PriorityQueue is not full, or not lessThan(element, top()).
   * @param element
   * @return true if element is added, false otherwise.
   */
  public boolean insert(Object element){
    if (size < maxSize){
      put(element);
      return true;
    }
    else if (size > 0 && !lessThan(element, top())){
      heap[1] = element;
      adjustTop();
      return true;
    }
    else
      return false;
  }
  /** Returns the least element of the PriorityQueue in constant time. */
  public final Object top() {
    if (size > 0)
      return heap[1];
    else
      return null;
  }
  /** Removes and returns the least element of the PriorityQueue in log(size)
      time. */
  public final Object pop() {
    if (size > 0) {
      Object result = heap[1];        // save first value
      heap[1] = heap[size];       // move last to first
      heap[size] = null;        // permit GC of objects
      size--;
      downHeap();         // adjust heap
      return result;
    } else
      return null;
  }
  /** Should be called when the Object at top changes values.  Still log(n)
   * worst case, but it"s at least twice as fast to <pre>
   *  { pq.top().change(); pq.adjustTop(); }
   * </pre> instead of <pre>
   *  { o = pq.pop(); o.change(); pq.push(o); }
   * </pre>
   */
  public final void adjustTop() {
    downHeap();
  }

  /** Returns the number of elements currently stored in the PriorityQueue. */
  public final int size() {
    return size;
  }
  /** Removes all entries from the PriorityQueue. */
  public final void clear() {
    for (int i = 0; i <= size; i++)
      heap[i] = null;
    size = 0;
  }
  private final void upHeap() {
    int i = size;
    Object node = heap[i];        // save bottom node
    int j = i >>> 1;
    while (j > 0 && lessThan(node, heap[j])) {
      heap[i] = heap[j];        // shift parents down
      i = j;
      j = j >>> 1;
    }
    heap[i] = node;         // install saved node
  }
  private final void downHeap() {
    int i = 1;
    Object node = heap[i];        // save top node
    int j = i << 1;         // find smaller child
    int k = j + 1;
    if (k <= size && lessThan(heap[k], heap[j])) {
      j = k;
    }
    while (j <= size && lessThan(heap[j], node)) {
      heap[i] = heap[j];        // shift up child
      i = j;
      j = i << 1;
      k = j + 1;
      if (k <= size && lessThan(heap[k], heap[j])) {
  j = k;
      }
    }
    heap[i] = node;         // install saved node
  }
}





Binary Heap Queue

/*
 * Copyright 2005 JBoss Inc
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.ruparator;
import java.util.NoSuchElementException;
public class BinaryHeapQueue implements Queue, Externalizable {
  /** The default capacity for a binary heap. */
  private final static int DEFAULT_CAPACITY = 13;
  /** The comparator used to order the elements */
  private Comparator comparator;
  /** The number of elements currently in this heap. */
  private int size;
  /** The elements in this heap. */
  private Queueable[] elements;
  public BinaryHeapQueue() {
  }
  /**
   * Constructs a new <code>BinaryHeap</code> that will use the given
   * comparator to order its elements.
   * 
   * @param comparator
   *          the comparator used to order the elements, null means use natural
   *          order
   */
  public BinaryHeapQueue(final Comparator comparator) {
    this(comparator, BinaryHeapQueue.DEFAULT_CAPACITY);
  }
  /**
   * Constructs a new <code>BinaryHeap</code>.
   * 
   * @param comparator
   *          the comparator used to order the elements, null means use natural
   *          order
   * @param capacity
   *          the initial capacity for the heap
   * @throws IllegalArgumentException
   *           if <code>capacity</code> is &lt;= <code>0</code>
   */
  public BinaryHeapQueue(final Comparator comparator, final int capacity) {
    if (capacity <= 0) {
      throw new IllegalArgumentException("invalid capacity");
    }
    // +1 as 0 is noop
    this.elements = new Queueable[capacity + 1];
    this.ruparator = comparator;
  }
  // -----------------------------------------------------------------------
  public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
    comparator = (Comparator) in.readObject();
    elements = (Queueable[]) in.readObject();
    size = in.readInt();
  }
  public void writeExternal(ObjectOutput out) throws IOException {
    out.writeObject(comparator);
    out.writeObject(elements);
    out.writeInt(size);
  }
  /**
   * Clears all elements from queue.
   */
  public void clear() {
    this.elements = new Queueable[this.elements.length]; // for gc
    this.size = 0;
  }
  /**
   * Tests if queue is empty.
   * 
   * @return <code>true</code> if queue is empty; <code>false</code>
   *         otherwise.
   */
  public boolean isEmpty() {
    return this.size == 0;
  }
  /**
   * Tests if queue is full.
   * 
   * @return <code>true</code> if queue is full; <code>false</code>
   *         otherwise.
   */
  public boolean isFull() {
    // +1 as Queueable 0 is noop
    return this.elements.length == this.size + 1;
  }
  /**
   * Returns the number of elements in this heap.
   * 
   * @return the number of elements in this heap
   */
  public int size() {
    return this.size;
  }
  /**
   * Inserts an Queueable into queue.
   * 
   * @param element
   *          the Queueable to be inserted
   */
  public synchronized void enqueue(final Queueable element) {
    if (isFull()) {
      grow();
    }
    percolateUpMinHeap(element);
  }
  /**
   * Returns the Queueable on top of heap and remove it.
   * 
   * @return the Queueable at top of heap
   * @throws NoSuchElementException
   *           if <code>isEmpty() == true</code>
   */
  public synchronized Queueable dequeue() throws NoSuchElementException {
    if (isEmpty()) {
      return null;
    }
    final Queueable result = this.elements[1];
    result.dequeue();
    // Code bellow was removed because it is already executed
    // inside result.dequeue()
    //
    // setElement(1, this.elements[this.size--]);
    // this.elements[this.size + 1] = null;
    //
    // if (this.size != 0) {
    // percolateDownMinHeap(1);
    // }
    return result;
  }
  /**
   * 
   * @param index
   */
  public synchronized Queueable dequeue(final int index) {
    if (index < 1 || index > this.size) {
      // throw new NoSuchElementException();
      return null;
    }
    final Queueable result = this.elements[index];
    setElement(index, this.elements[this.size]);
    this.elements[this.size] = null;
    this.size--;
    if (this.size != 0 && index <= this.size) {
      int compareToParent = 0;
      if (index > 1) {
        compareToParent = compare(this.elements[index], this.elements[index / 2]);
      }
      if (index > 1 && compareToParent < 0) {
        percolateUpMinHeap(index);
      } else {
        percolateDownMinHeap(index);
      }
    }
    return result;
  }
  /**
   * Percolates Queueable down heap from the position given by the index. <p/>
   * Assumes it is a minimum heap.
   * 
   * @param index
   *          the index for the Queueable
   */
  private void percolateDownMinHeap(final int index) {
    final Queueable element = this.elements[index];
    int hole = index;
    while ((hole * 2) <= this.size) {
      int child = hole * 2;
      // if we have a right child and that child can not be percolated
      // up then move onto other child
      if (child != this.size && compare(this.elements[child + 1], this.elements[child]) < 0) {
        child++;
      }
      // if we found resting place of bubble then terminate search
      if (compare(this.elements[child], element) >= 0) {
        break;
      }
      setElement(hole, this.elements[child]);
      hole = child;
    }
    setElement(hole, element);
  }
  /**
   * Percolates Queueable up heap from the position given by the index. <p/>
   * Assumes it is a minimum heap.
   * 
   * @param index
   *          the index of the Queueable to be percolated up
   */
  private void percolateUpMinHeap(final int index) {
    int hole = index;
    final Queueable element = this.elements[hole];
    while (hole > 1 && compare(element, this.elements[hole / 2]) < 0) {
      // save Queueable that is being pushed down
      // as the Queueable "bubble" is percolated up
      final int next = hole / 2;
      setElement(hole, this.elements[next]);
      hole = next;
    }
    setElement(hole, element);
  }
  /**
   * Percolates a new Queueable up heap from the bottom. <p/> Assumes it is a
   * minimum heap.
   * 
   * @param element
   *          the Queueable
   */
  private void percolateUpMinHeap(final Queueable element) {
    setElement(++this.size, element);
    percolateUpMinHeap(this.size);
  }
  /**
   * Compares two objects using the comparator if specified, or the natural
   * order otherwise.
   * 
   * @param a
   *          the first object
   * @param b
   *          the second object
   * @return -ve if a less than b, 0 if they are equal, +ve if a greater than b
   */
  private int compare(final Queueable a, final Queueable b) {
    return this.ruparator.rupare(a, b);
  }
  /**
   * Increases the size of the heap to support additional elements
   */
  private void grow() {
    final Queueable[] elements = new Queueable[this.elements.length * 2];
    System.arraycopy(this.elements, 0, elements, 0, this.elements.length);
    this.elements = elements;
  }
  /**
   * 
   * @param index
   * @param element
   */
  private void setElement(final int index, final Queueable element) {
    this.elements[index] = element;
    element.enqueued(this, index);
  }
  public Queueable[] getQueueable() {
    return this.elements;
  }
  public Object[] toArray() {
    final Object[] result = new Object[this.size];
    System.arraycopy(this.elements, 1, result, 0, this.size);
    return result;
  }
  public Object[] toArray(Object a[]) {
    if (a.length < this.size) {
      a = (Object[]) java.lang.reflect.Array
          .newInstance(a.getClass().getComponentType(), this.size);
    }
    System.arraycopy(this.elements, 1, a, 0, this.size);
    if (a.length > this.size) {
      a[this.size] = null;
    }
    return a;
  }
}
/*
 * Copyright 2005 JBoss Inc
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
interface Queue {
  public void enqueue(Queueable queueable);
  public Queueable dequeue();
  public Queueable dequeue(int index);
  public boolean isEmpty();
}
/*
 * Copyright 2005 JBoss Inc
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
interface Queueable {
  public void enqueued(Queue queue, int index);
  public void dequeue();
}





Checking what item is first in line without removing it: element

import java.util.LinkedList;
import java.util.Queue;
public class Main {
    public static void main(String[] args) {
        Queue<String> queue = new LinkedList<String>();
        
        queue.add("A");
        queue.add("B");
        
        queue.offer("C");
        queue.offer("D");
        System.out.println("remove: " + queue.remove());
        System.out.println("element: " + queue.element());
        
        System.out.println("poll: " + queue.poll());
        System.out.println("peek: " + queue.peek());
    }
}
/*
remove: A
element: B
poll: B
peek: C
*/





Circular Queue

/*   Copyright 2004 BEA Systems, Inc.
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 */

import java.util.AbstractCollection;
import java.util.Arrays;
import java.util.ConcurrentModificationException;
import java.util.Iterator;
import java.util.NoSuchElementException;
public final class CircularQueue extends AbstractCollection {
  // This is the largest capacity allowed by this implementation
  private static final int MAX_CAPACITY = 1 << 30;
  private static final int DEFAULT_CAPACITY = 1 << 8;
  private int size          = 0;
  private int producerIndex = 0;
  private int consumerIndex = 0;
  // capacity must be a power of 2 at all times
  private int capacity;
  private int maxCapacity;
  // we mask with capacity -1.  This variable caches that values
  private int bitmask; 
  private Object[] q;
  public CircularQueue() {
    this(DEFAULT_CAPACITY);
  }
  // Construct a queue which has at least the specified capacity.  If
  // the value specified is a power of two then the queue will be
  // exactly the specified size.  Otherwise the queue will be the
  // first power of two which is greater than the specified value.
  public CircularQueue(int c) {
    this(c, MAX_CAPACITY);
  }
  public CircularQueue(int c, int mc) {
    if (c > mc) {
      throw new IllegalArgumentException("Capacity greater than maximum");
    }
    if (mc > MAX_CAPACITY) {
      throw new IllegalArgumentException("Maximum capacity greater than " +
        "allowed");
    }
    for (capacity = 1; capacity < c; capacity <<= 1) ;
    for (maxCapacity = 1; maxCapacity < mc; maxCapacity <<= 1) ;
    bitmask = capacity - 1;
    q = new Object[capacity];
  }
  // Constructor used by clone()
  private CircularQueue(CircularQueue oldQueue) {
    size = oldQueue.size;
    producerIndex = oldQueue.producerIndex;
    consumerIndex = oldQueue.consumerIndex;
    capacity = oldQueue.capacity;
    maxCapacity = oldQueue.maxCapacity;
    bitmask = oldQueue.bitmask;
    q = new Object[oldQueue.q.length];
    System.arraycopy(oldQueue.q, 0, q, 0, q.length);
  }
  private boolean expandQueue() {
    // double the size of the queue
    // This design assumes that this is a rare case
    if (capacity == maxCapacity) {
      return false;
    }
    int old_capacity = capacity;
    Object[] old_q    = q;
    capacity += capacity;
    bitmask   = capacity - 1;
    q         = new Object[capacity];
    System.arraycopy(old_q, consumerIndex, q, 0, old_capacity - consumerIndex);
    if (consumerIndex != 0) {
      System.arraycopy(old_q, 0, q, old_capacity - consumerIndex, 
        consumerIndex);
    }
    consumerIndex = 0;
    producerIndex = size;
    return true;
  }
  public boolean add(Object obj) {
    if (size == capacity) {
      // no room
      if (!expandQueue()) return false;
    }
    size++;
    q[producerIndex] = obj;
    producerIndex = (producerIndex + 1) & bitmask;
    return true;
  }
  public Object remove() {
    Object obj;
    
    if (size == 0) return null;
    
    size--;
    obj = q[consumerIndex];
    q[consumerIndex] = null; // allow gc to collect
    
    consumerIndex = (consumerIndex + 1) & bitmask;
    return obj;
  }
  public boolean isEmpty() { return size == 0; }
  public int size() { return size; }
  public int capacity() { return capacity; }
  public Object peek() {
    if (size == 0) return null;
    return q[consumerIndex];
  }
  public void clear() {
    Arrays.fill(q, null);
    size = 0;
    producerIndex = 0;
    consumerIndex = 0;
  }
  public Object clone() {
    return new CircularQueue(this);
  }
  public String toString() {
    StringBuffer s = new StringBuffer(super.toString() + " - capacity: "" +
      capacity() + "" size: "" + size() + """);
    if (size > 0) {
      s.append(" elements:");
      for (int i = 0; i < size; ++i) {
        s.append("\n");
        s.append("\t");
        s.append(q[consumerIndex + i & bitmask].toString());
      }      
    }
    return s.toString();
  }
  public Iterator iterator() {
    return new Iterator() {
      private final int ci = consumerIndex;
      private final int pi = producerIndex;
      private int s = size;
      private int i = ci;
      public boolean hasNext() {
        checkForModification();
        return s > 0;
      }
      public Object next() {
        checkForModification();
        if (s == 0) throw new NoSuchElementException();
    
        s--;
        Object r = q[i];
        i = (i + 1) & bitmask;
        return r;
      }
      public void remove() {
        throw new UnsupportedOperationException();
      }
      private void checkForModification() {
        if (ci != consumerIndex) throw new ConcurrentModificationException();
        if (pi != producerIndex) throw new ConcurrentModificationException();
      }
    };
  }
}





Convert a Queue to a List

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
public class Main {
  public static void main(String[] args) {
    Queue<String> myQueue = new LinkedList<String>();
    myQueue.add("A");
    myQueue.add("B");
    myQueue.add("C");
    myQueue.add("D");
    List<String> myList = new ArrayList<String>(myQueue);
    for (Object theFruit : myList)
      System.out.println(theFruit);
  }
}
/*
A
B
C
D
*/





Create a queue using LinkedList class

import java.util.LinkedList;
import java.util.Queue;
public class Main {
  public static void main(String[] args) {
    Queue<String> queue = new LinkedList<String>();
    queue.offer("First");
    queue.offer("Second");
    queue.offer("Third");
    queue.offer("Fourth");
    System.out.println("Size: " + queue.size());
    System.out.println("Queue head using peek   : " + queue.peek());
    System.out.println("Queue head using element: " + queue.element());
    Object data;
    while ((data = queue.poll()) != null) {
      System.out.println(data);
    }
  }
}





Synchronized Queue

/*
 * Copyright (c) 2003 - 2007 OpenSubsystems s.r.o. Slovak Republic. All rights reserved.
 * 
 * Project: OpenSubsystems
 * 
 * $Id: SynchronizedQueue.java,v 1.4 2007/01/07 06:14:00 bastafidli Exp $
 * 
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; version 2 of the License. 
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
 */

import java.util.LinkedList;
import java.util.List;
/**
 * Class that implement unlimited queue, that is synchronized. It means that
 * the consumer of the objects from the queue waits/is blocked in the get 
 * method until there is an object available.
 *
 * @version $Id: SynchronizedQueue.java,v 1.4 2007/01/07 06:14:00 bastafidli Exp $
 * @author Miro Halas
 * @code.reviewer Miro Halas
 * @code.reviewed Initial revision
 */
public class SynchronizedQueue
{
   // Attributes ///////////////////////////////////////////////////////////////
   
   /**
    * Cache of object produced by producer and consumed by consumer.
    */
   protected List m_lstObjects;
   // Constructors /////////////////////////////////////////////////////////////
   
   /**
    * Constructor for Synchronized Queue Object.
    */
   public SynchronizedQueue(
   )
   {
      super();
      m_lstObjects = new LinkedList();
   }
   // Logic ////////////////////////////////////////////////////////////////////
   
   /**
    * Destructor for Synchronized Queue. It is called when no other
    * object holds reference to it.
    *
    * @exception Throwable - default destructor exception
    */
   protected void finalize(
   ) throws Throwable
   {
      // Explicitely remove this just to help garbage collector
      m_lstObjects.clear();
      m_lstObjects = null;
      super.finalize();
   }
   /**
    * Get the object from the beginning of the queue
    *
    * @return Object - object from the queue, if the thread is blocked in this
    *                  function and you call interrupt method, an InterruptedException
    *                  will be thrown.
    * @exception InterruptedException - if the thread is blocked in this
    *                                   function and you call interrupt method,
    *                                   an InterruptedException will be thrown.
    */
   public synchronized Object get(
   ) throws InterruptedException
   {
      Object objReturn = null;
      if (m_lstObjects.isEmpty())
      {
         // There is no object in the queue, go to sleep
         try
         {
            wait();
         }
         catch (InterruptedException ieException)
         {
            // Somebody woke us up, that means all threads waiting on this
            // object competed for the lock and this one won and the object is
            // locked again
            // The thread can be woken up in two conditions, producer put new
            // object into the queue or somebody called interrupt - to interrupt
            // the wait - in this case rethrow an exception
            if (m_lstObjects.isEmpty())
            {
               throw ieException;
            }
         }
      }
      // Remove the first object in the queue
      objReturn = m_lstObjects.remove(0);
      return objReturn;
   }
   /**
    * Put the object to the end of the queue.
    *
    * @param objNew - new object, can be null
    */
   public synchronized void put(
      Object objNew
   )
   {
      m_lstObjects.add(objNew);
      // New object in the queue, notify others
      notifyAll();
   }
   /**
    * Test if the queue is empty.
    *
    * @return boolean - true if the queue is empty
    */
   public synchronized boolean isEmpty(
   )
   {
      return m_lstObjects.isEmpty();
   }
}





Use the Stack class in Java

import java.util.Stack;
public class Main {
  public static void main(String[] args) {
    Stack<Integer> stack = new Stack<Integer>();
    for (int i = 0; i < 10; i++) {
      stack.push(i);
      System.out.print(i + " ");
    }
    System.out.println("");
    int position = stack.search(3);
    System.out.println("Search result position: " + position);
    System.out.println("Stack top: " + stack.peek());
    while (!stack.empty()) {
      System.out.print(stack.pop() + " ");
    }
  }
}