package comp2402a2; import java.util.AbstractQueue; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Random; import java.util.NoSuchElementException; /** * An implementation of a RandomQueue. This is like a standard queue, * except that when we remove an element, we get a random element. * * TODO: This implementation requires Theta(size) time on average for * poll() operation. Improve this so that it takes constant time. * @author morin * * @param the type of elements stored in the queue */ public class RandomQueue extends AbstractQueue { /** * The list that stores our queue elements */ List l; /** * A source of random numbers */ Random r; /** * The index of the next element we will return */ int next; int j=0;//index start int k=0;//size of the list public RandomQueue() { l = new ArrayList(); r = new Random(); } /** * Return an iterator for the elements in the queue * Note: this iterator does not necessarily enumerate the elements * in random order */ public Iterator iterator() { return l.iterator(); } public int size() { return k; } public boolean add(T x) { if(k==0) { l.add(x); k++; return true; } if(k+1 > l.size()) resize(); l.set((j+k)%l.size(), x); k++; return true; } void resize() {//make the ArrayList bigger (not sure if needed or not List b = new ArrayList(k*2); for(int i=0; i0; i--){ l.set(i, l.get(i-1)); } j++; k--; } else { //shift left for(int i=z; i= 0 && next <= l.size()-1); return l.get(next); } /** * Remove and return a random element from the queue */ public T poll() { peek(); T x = remove1(next); next = (l.size() > 0) ? r.nextInt(l.size()) : -1; return x; } public T remove(){ return poll(); } /** * A stupid method to help with tests * @param b * @throws AssertionError */ protected static void myassert(boolean b) throws AssertionError { if (!b) { throw new AssertionError(); } } /** * Some test code * @param args ignored */ public static void main(String[] args) { RandomQueue q = new RandomQueue(); // some simple tests and output to check for randomness int n = 16; for (int j = 0; j < 5; j++) { for (int i = 0; i < n; i++) { q.add(i); } boolean[] checked = new boolean[n]; for (int i = 0; i < n; i++) { myassert(q.size() == n-i); Integer k = q.remove();//this would most likely be the offending line myassert(checked[k] == false);//due to this being the error producing line checked[k] = true; System.out.print(k); if (q.isEmpty()) { System.out.println(); } else { System.out.print(","); } } myassert(q.isEmpty()); } // heavier-duty tests to check for randomness n = 10000; for (int i = 0; i < n; i++) { q.add((i % 2 == 0) ? i : n+i); } boolean[] checked = new boolean[n]; Integer max = -1; int records = 0; for (int i = 0; i < n; i++) { myassert(q.size() == n-i); Integer k = q.remove(); k = (k > n) ? k - n : k; if (k > max) { max = k; records++; } myassert(checked[k] == false); checked[k] = true; } myassert(q.isEmpty()); System.out.println("# records = " + records + " (expected " + Math.log(n) + ")"); // some performance tests n = 100000; System.out.print("Adding " + n + " elements..."); long start = System.nanoTime(); for (int i = 0; i < n; i++) { q.add(i); } long stop = System.nanoTime(); double elapsed = 1e-9*(stop-start); System.out.println("done (" + elapsed + "s) [ " + (int)(((double)n)/elapsed) + " ops/sec ]"); Random r = new Random(); System.out.print("Performing " + 5*n + " queue operations..."); start = System.nanoTime(); for (int i = n; i < 5*n; i++) { if (r.nextBoolean() == false) { q.remove(); } else { q.add(i); } } stop = System.nanoTime(); elapsed = 1e-9*(stop-start); System.out.println("done (" + elapsed + "s) [ " + (int)(((double)n)/elapsed) + " ops/sec ]"); } }