1 CSE 143 Lecture 1: ArrayList reading: 10.1. 2 Welcome to CSE 143! I'm Allison Obourn .
CSE 143 Lecture 10
description
Transcript of CSE 143 Lecture 10
CSE 143Lecture 10
Generics,Stack, Queue
Based on slides by Alyssa Harding
Review: ArrayIntList client
• Now that we’ve built ArrayIntList , we can be its client
ArrayIntList list1 = new ArrayIntList(); list1.add(42); list1.add(7); list1.add(-10);
for (int i = 0; i < list1.size(); i++) { System.out.println(list1.get(i)); }
Generics
• But what if we want to have a list of Strings?
• We could copy ArrayIntList and change it into ArrayStringList…
• Java to the rescue: Generics!
Redundant!
ArrayList<E> uses Generics
• <E> is a type parameter
ArrayList<E>
•ArrayList<E> has all the methods we want:
// adds given value to end of list
void add(E value)
// adds given value at the given index
void add(E value, int index)
// removes value at the given index
void remove(int index)
// returns value at given index
E get(int index)
// returns size of list
int size()
E is the Element type
ArrayList<E>
• Now we can create and use a list of any type of Object:
ArrayList<String> list = new ArrayList<String>();
list.add(“hello”);
String s = list.get(0);
• However, this only works for Objects, not primitive data types, such as ints or doubles
Wrapper classes
• Java has classes that wrap the primitive types in objects:
• Example of autoboxing:ArrayList<Integer> list = new ArrayList<Integer>();
list.add(42);
int x = list.get(0);
primitive type object type
int Integer
double Double
char Character
boolean Boolean
ArrayList<E> client
• Now we can get back to our client code
ArrayList<Integer> list1 = new ArrayList<Integer>(); list1.add(42); list1.add(7); list1.add(-10);
for (int i = 0; i < list1.size(); i++) { System.out.println(list1.get(i)); }
Stacks & Queues
Stacks and Queues
• Sometimes it is good to have a collection that is less powerful, but is optimized to perform certain operations very quickly.
• Today we will examine two specialty collections:– stack: Retrieves elements in the reverse of the order they were
added.– queue: Retrieves elements in the same order they were added.
stack
queue
Abstract data types (ADTs)
• abstract data type (ADT): A specification of a collection of data and the operations that can be performed on it.– Describes what a collection does, not how it does it
• We don't know exactly how a stack or queue is implemented, and we don't need to.– We just need to understand the idea of the collection and
what operations it can perform.
(Stacks are usually implemented with arrays; queues are often implemented with a linked list.)
Stacks
• stack: A collection based on the principle of adding elements and retrieving them in the opposite order.– Last-In, First-Out ("LIFO")– The elements are stored in order of insertion,
but we do not think of them as having indexes.– The client can only add/remove
the last element added (the "top").
• basic stack operations:– push: Add an element to the top.– pop: Remove the top element.
Stacks in computer science
• Programming languages and compilers:– method calls are placed onto a stack (call=push, return=pop)– compilers use stacks to evaluate expressions
• Matching up related pairs of things:– find out whether a string is a palindrome– examine a file to see if its braces { } and other operators
match– convert "infix" expressions to "postfix" or "prefix"
• Sophisticated algorithms:– searching through a maze with "backtracking"– many programs use an "undo stack" of previous operations
method3
return varlocal varsparameters
method2
return varlocal varsparameters
method1
return varlocal varsparameters
Queues
• queue: Retrieves elements in the order they were added.– First-In, First-Out ("FIFO")– Elements are stored in order of
insertion but don't have indexes.– Client can only add to the end of the
queue, and can only removethe front of the queue.
• basic queue operations:– enqueue: Add an element to the back.– dequeue: Remove the front element.
queue
Queues in computer science
• Operating systems:– queue of print jobs to send to the printer– queue of programs / processes to be run– queue of network data packets to send
• Programming:– modeling a line of customers or clients– storing a queue of computations to be performed in order
• Real world examples:– people on an escalator or waiting in a line– cars at a gas station (or on an assembly line)
16
Stacks
• Stacks are a Last In First Out (LIFO) structure
// add value to the top of the stack
void push(E value)
// remove and return the value at the top
E pop()
// return the size
int size()
// return whether the stack is empty
boolean isEmpty()
17
Queues
• Queues are a First In First Out (FIFO) structure
// add value to the back of the queue
void enqueue(E value)
// remove and return the value at the front
E dequeue()
// return the size
int size()
// return whether the queue is empty
boolean isEmpty()
18
Interfaces & Implementations
Important!!• We’re using our own Stack<E> and Queue<E> interfaces
• We’re using our own ArrayStack<E> and LinkedQueue<E> implementations (classes)
• We are using generics with both the interfaces and the implementations, so we can store any type of Object in them
• Note: There are other implementations (and interfaces) of stacks and queues in the Java collections. They have more method and use different names for the methods. We are NOT using these!
19
Our Stack Interface
public interface Stack<E> {
public void push(E value);
public E pop();
public int size();
public boolean isEmpty();
}
20
Our Queue Interface
public interface Queue<E> {
public void enqueue(E value);
public E dequeue(); public int size();
public boolean isEmpty(); }
21
Stack and Queue client
Stack<Integer> s = new ArrayStack<Integer>();
Queue<Integer> q = new LinkedQueue<Integer>();
for (int i = 0; i < 3; i++) {
s.push(i);
q.enqueue(i);
}
System.out.println("stack = " + s); System.out.println("queue = " + q);
22
What does this do?Stack<Integer> s = new ArrayStack<Integer>();
Queue<Integer> q = new LinkedQueue<Integer>();
for (int i = 0; i < 3; i++) {
s.push(i);
q.enqueue(i);
}
System.out.println(s.pop());
System.out.println("stack = " + s);
System.out.println(q.dequeue());
System.out.println("queue = " + q);
23
Stack and Queue client methods: fillQueue
• We might want to fill a Queue with values:
public static Queue<Integer> fillQueue(int n) { Queue<Integer> q = new LinkedQueue<Integer>();
return q;
}
Note that the variable declaration and return value use the interface type
24
Stack and Queue client methods: fillQueue
• We might want to fill a Queue with values:
public static Queue<Integer> fillQueue(int n) { Queue<Integer> q = new LinkedQueue<Integer>(); for (int i = 0; i < n; i++) { q.enqueue(i);
} return q;
}
Note that the variable declaration and return value use the interface type
25
Stack and Queue client methods: queueToStack
• We might want to move values from a Queue to a Stack:
public static void queueToStack(
Queue<Integer> q, Stack<Integer> s) {
while ( ) {
}
}
26
Stack and Queue client methods: queueToStack
• We might want to move values from a Queue to a Stack:
public static void queueToStack(
Queue<Integer> q, Stack<Integer> s) {
while ( !q.isEmpty() ) { int n = q.dequeue(); s.push(n); }
}
Boolean zen!
27
Stack and Queue client methods: sum (first
attempt)• We might want to sum the values in a Queue:
public static int sum(Queue<Integer> q) { int sum = 0; while ( !q.isEmpty() ) { sum += q.dequeue(); }
return sum;
}
28
Stack and Queue client methods: sum (first
attempt)• We might want to sum the values in a Queue:
public static int sum(Queue<Integer> q) { int sum = 0; while ( !q.isEmpty() ) { sum += q.dequeue(); }
return sum;
}
But this destroys the Queue and leaves it empty!
29
Stack and Queue client methods: sum (2nd
attempt)• We might want to sum the values in a Queue:
public static int sum(Queue<Integer> q) { int sum = 0; for ( ) {
} return sum;
}
30
Stack and Queue client methods: sum
• We might want to sum the values in a Queue:
public static int sum(Queue<Integer> q) { int sum = 0; for (int i = 0; i < q.size(); i++) { int n = q.dequeue(); sum += n; q.enqueue(n); } return sum;
}
So we store values back in the Queue and loop the correct number of times.
31
Stack and Queue client methods: fillStack
• We might also want to fill a Stack:
public static Stack<Integer> fillStack(int n) { Stack<Integer> s = new ArrayStack<Integer>(); for (int i = 0; i < n; i++)
return s;
}
We can copy the Queue code and change it to use a Stack.
32
Stack and Queue client methods: fillStack
• We might also want to fill a Stack:
public static Stack<Integer> fillStack(int n) { Stack<Integer> s = new ArrayStack<Integer>(); for (int i = 0; i < n; i++) s.push(i); return s;
}
We can copy the Queue code and change it to use a Stack.
33
Stack and Queue client methods: stackToQueue
• We might also want to move values from a Stack to a Queue:
public static void stackToQueue(
Stack<Integer> s, Queue<Integer> q) {
while ( !s.isEmpty() ) { int n = s.pop(); q.enqueue(n); }
}
We can copy the Queue code and change it to use a Stack.
34
Stack and Queue client methods: sum (first
attempt)• We might want to sum the values in a Stack:
public static int sum(Stack<Integer> s) { int sum = 0; for (int i = 0; i < s.size(); i++) { int n = s.pop(); sum += n; s.push(n); } return sum;
}
What is wrong with this code?
35
Stack and Queue client methods: sum (first
attempt)• We might want to sum the values in a Stack:
public static int sum(Stack<Integer> s) { int sum = 0; for (int i = 0; i < s.size(); i++) { int n = s.pop(); sum += n; s.push(n); } return sum;
}
But if we copy the Queue code, we push and pop the same value over and over.
36
Stack and Queue client methods: sum (2nd
attempt)• We might want to sum the values in a Stack:
public static int sum(Stack<Integer> s) { int sum = 0; Queue<Integer> q = new LinkedQueue<Integer>(); for (int i = 0; i < s.size(); i++) { int n = s.pop(); sum += n; q.enqueue(n); }
queueToStack(q,s); return sum;
} Does this work?
37
Stack and Queue client methods: sum (2nd
attempt)• We might want to sum the values in a Stack:
public static int sum(Stack<Integer> s) { int sum = 0; Queue<Integer> q = new LinkedQueue<Integer>(); for (int i = 0; i < s.size(); i++) { int n = s.pop(); sum += n; q.enqueue(n); }
queueToStack(q,s); return sum;
}
Even though we store values in a Queue, i
increases and s.size() decreases, so we only
examine half the values
38
Stack and Queue client methods: sum (3rd attempt)
• We might want to sum the values in a Stack:
public static int sum(Stack<Integer> s) { int sum = 0; Queue<Integer> q = new LinkedQueue<Integer>(); while ( !s.isEmpty() ) { int n = s.pop(); sum += n; q.enqueue(n); } queueToStack(q,s); return sum;
}Does this work?
39
Stack and Queue client methods: sum (3rd attempt)
• We might want to sum the values in a Stack:
public static int sum(Stack<Integer> s) { int sum = 0; Queue<Integer> q = new LinkedQueue<Integer>(); while ( !s.isEmpty() ) { int n = s.pop(); sum += n; q.enqueue(n); } queueToStack(q,s); return sum;
}
Now the sum is correct, but our
resulting Stack is reversed! This
happens when we transfer from a Stack
to Queue and back.
40
Stack and Queue client methods: sum (final
version)• We might want to sum the values in a Stack:
public static int sum(Stack<Integer> s) { int sum = 0; Queue<Integer> q = new LinkedQueue<Integer>(); while ( !s.isEmpty() ) { int n = s.pop(); sum += n; q.enqueue(n); }
queueToStack(q,s);
stackToQueue(s,q);
queueToStack(q,s); return sum;
}
Now both the sum and the Stack are
correct.
41
Stack and Queue client methods: findMin
• We might want to find the minimum value in a Stack:
public static int findMin(Stack<Integer> s) { int min = 0; Queue<Integer> q = new LinkedQueue<Integer>(); while ( !s.isEmpty() ) { int n = s.pop(); if ( n < min ) min = n; q.enqueue(n); } queueToStack(q,s); stackToQueue(s,q); queueToStack(q,s); return min;
}
Does this work?
42
Stack and Queue client methods: findMin
• We might want to find the minimum value in a Stack:
public static int findMin(Stack<Integer> s) { int min = 0; Queue<Integer> q = new LinkedQueue<Integer>(); while ( !s.isEmpty() ) { int n = s.pop(); if ( n < min ) min = n; q.enqueue(n); } queueToStack(q,s); stackToQueue(s,q); queueToStack(q,s); return min;
}
What if the values in the Stack are all greater than 0? This would still return
0 as the minimum.
43
Stack and Queue client methods: findMin(final
version)• We might want to find the minimum value in a Stack:
public static int findMin(Stack<Integer> s) { Queue<Integer> q = new LinkedQueue<Integer>();
int min = s.pop();
s.push(min); while ( !s.isEmpty() ) { int n = s.pop(); if ( n < min ) min = n; q.enqueue(n); } queueToStack(q,s); stackToQueue(s,q); queueToStack(q,s); return min; }
Instead, we start our minimum at a value that
is in the Stack.
44
Preconditions
• Remember the precondition of Stack’s pop method?
• The Stack cannot be empty when we call pop
• Since we call pop in our method without checking that the Stack isn’t empty, our method has this precondition too
45
Preconditions
• How are we going to deal with this?
• We need to return a value, but what would we return if we were passed an empty Stack?
• We can comment this precondition, but that doesn’t stop clients from using our method incorrectly
46
Exceptions
• Java lets us throw exceptions in our methods:throw new <exception type here>();
• In this case, we want to throw an exception if the method was given an illegal argument, so we throw an IllegalArgumentException:
if ( s.isEmpty() ) throw new IllegalArgumentException();
47
Exceptions
• Always comment the type and cause of any exceptions you throw:
// throws IllegalArgumentException if the
// stack is empty