07b: Queue ADT

ICS211, Spring 2013
Dr. Zach

(switch view)

Status

Trimming unnecessary code (tips from Exam 1)

Queue ADT

Queue Behavior

Method names not as standardized as for stack

Queue Use

Queue<Integer> q = new Queue<Integer>();
q.offer(4);
q.offer(7);
q.offer(9);
System.out.println(q.size());  // 3
System.out.println(q.peek());  // 4
q.poll();                     
System.out.println(q.poll());  // 7

Implementation options

Array-based Queue

Array-based Queue Implementation

public class Queue<E> {

  private static final int CAPACITY = 5;

  private E[] items;
  private int front;  //points at first item
  private int back;   //first blank spot

  public Queue() {
    //use one extra cell so never full, so front == back always means empty
    @SuppressWarnings("unchecked")  //more on this later...
    E[] array = (E[]) new Object[CAPACITY + 1];
    items = array;
    back = 0;
    front = 0;
  }

  public void offer(E item) {
    if (this.size() == CAPACITY) {
      //Implementation-level restriction: would be nice to avoid this...
      throw new IllegalStateException("Queue is full.");
    }
    this.items[back] = item;
    this.back = (this.back + 1) % items.length;
  }

  public E peek() {
    if (this.size() == 0) {
      throw new IllegalStateException("Queue is empty.");
    }
    return this.items[front];
  }

  public E poll() {
    E item = this.peek();  //throws exception if empty
    this.front = (this.front + 1) % items.length;
    return item;
  }

  public int size() {
    return (this.back + items.length - this.front) % items.length;
  }
}

Big-Os?

Array-based Queue - Growth

Node-based Queue implementation

Other Queue options?

ADT behavior vs efficiency

Java: Generics

Revisited

Pre-generics ArrayList use

Also before autoboxing

public static void main(String[] args) {
  ArrayList numbers = new ArrayList();
  numbers.add(new Integer(2));
  numbers.add(new Integer(4));
  numbers.add(new Integer(5));
  int total = product(numbers);
  System.out.println(total);
}

public static int product(ArrayList nums) {
  int product = 1;
  for (int i = 0; i < nums.size(); i++) {
    Integer n = (Integer) nums.get(i); //nums.get(i) returns an Object
    product *= n.intValue();
  }
  return product;
}

Modern ArrayList use

(Still no autoboxing in this example)

public static void main(String[] args) {
  ArrayList<Integer> numbers = new ArrayList<Integer>();
  numbers.add(new Integer(2));
  numbers.add(new Integer(4));
  numbers.add(new Integer(5));
  int total = product(numbers);
  System.out.println(total);
}

public static int product(ArrayList<Integer> nums) {
  int product = 1;
  for (int i = 0; i < nums.size(); i++) {
    Integer n = nums.get(i); //no cast; returns Integer now
    product *= n.intValue();
  }
  return product;
}

Very modern ArrayList use

Autoboxing, for-each loop

public static void main(String[] args) {
  ArrayList<Integer> numbers = new ArrayList<Integer>();
  numbers.add(2);
  numbers.add(4);
  numbers.add(5);
  int total = product(numbers);
  System.out.println(total);
}

public static int product(ArrayList<Integer> nums) {
  int product = 1;
  for (int n : nums) {
    product *= n;
  }
  return product;
}

Old way: Implement Queue

Still general purpose: Can insert any kind of object

class Queue {  //no <E>

  private static final int CAPACITY = 5;

  private Object[] items;
  private int front;  //points at first item
  private int back;   //first blank spot

  public Queue() {
    Object[] array = new Object[CAPACITY + 1];
    items = array;
    back = 0;
    front = 0;
  }

  public void offer(Object item) {
    if (this.size() == CAPACITY) {
      //Implementation-level restriction: would be nice to avoid this...
      throw new IllegalStateException("Queue is full.");
    }
    this.items[back] = item;
    this.back = (this.back + 1) % items.length;
  }

  public Object peek() {
    if (this.size() == 0) {
      throw new IllegalStateException("Queue is empty.");
    }
    return this.items[front];
  }

  public Object poll() {
    Object item = this.peek();  //throws exception if empty
    this.front = (this.front + 1) % items.length;
    return item;
  }

  public int size() {
    return (this.back + items.length - this.front) % items.length;
  }
}

Old way: Using Queue

  public static void main(String[] args) {
    Queue q = new Queue();
    q.offer("here");
    q.offer("there");
    q.offer(4.3);  //autoboxed -> Integer -> Object

    //...

    while (q.size() > 0) {
      Object o = q.poll();              //every thing comes out as Object
      String str = (String) o;          //need to cast back to what you put in ->
      System.out.println(str.length()); //  crash: ClassCastException
    }
  }

Type Erasure

Generic array creation

class Queue<E> {

  private static final int CAPACITY = 5;

  private E[] items;
  private int front;  
  private int back; 

  public Queue() {
    this.items = new E[CAPACITY];  //NO!  Does not compile
    this.front = 0;
    this.back = 0;
  }
}

Compiler can't put a specific E here: Integer, String, what? Needs one type that works for all Stack uses.

  E example = new E();  //NO: which constructor would get called?
  
  public E[] snapshot() {
    return items;       //NO: Object[]?  
                        //But (new Queue<String>()).snapshot() should give String[]
                        //and (new Queue<Integer>()).snapshot() should give Integer[]
  }

Generic array creation

  this.items = new E[CAPACITY];  //NO!  Does not compile

  this.items = new Object[CAPACITY];  //NO!  E[] != Object[]

  this.items = (E[]) new Object[CAPACITY];  //Works... but warning
    @SuppressWarnings("unchecked")
    E[] array = (E[]) new Object[CAPACITY];
    this.items = array;

Arrays of parametized types

Conclusions

More info: Java Tutorial, Arrays in Java Generics

Method call series

Given:

ArrayList<PyramidStack<Meep>> shafts = new ArrayList<PyramidStack<Meep>>();
//... add three new PyramidStack<Meep>()s
Meep newcomer = new Meep(5);  //Meeps are Comparable, so has compareTo method.

Problem: See if meep on top of left shaft (index: 0) is smaller than newcomer

   (shafts)                  //whole ArrayList
   (shafts.get(2))           //first PyramidStack<Meep>
   (shafts.get(2).peek())    //Top of that stack: a Meep
   (shafts.get(2).peek().compareTo(newcomer))   //an int
  if (shafts.get(2).peek().compareTo(newcomer) < 0) {
    //top meep is smaller

Shortcut logic operators

  if (shafts.get(2).peek().compareTo(newcomer) < 0) {
    //top meep is smaller

Now we have 3 stacks in shafts, but what if stack at shaft.get(2) is empty? Crash!

  if (shafts.get(2).size() > 0 && 
      shafts.get(2).peek().compareTo(newcomer) < 0) {
    //...
  if (shafts.get(2).size() == 0 ||
      shafts.get(2).peek().compareTo(newcomer) < 0) {
    //newcomer can move to first shaft

Summary

For next time...