Lecture 10:
H4 and
P2 due on Tuesday (
questions
about P2?
Exam: next Thursday,
·
covers
through stacks & queues
·
one
page of notes (handwritten or typed)
·
practice
exams on-line; review
in class on Tues
Alternate exam time: see me
Stacks & Queues
·
Both
similar to List, but with restricted operations
·
Both
can be implemented using arrays or linked lists
Stack:
conceptual picture
(think of stack of trays
PUSH values in
in the cafeteria)
·
Access
only to top item
-
a
“last-in first-out” (LIFO) data structure
operations:
boolean empty()
int size()
void push(Object ob)
Object pop() // error if Stack is empty
Object peek() // error if
Stack is empty
Queue
Conceptual
picture:
·
new
item added only at the back of the queue
·
items
can be removed only from the front of the queue
·
a
“first-in first-out” (FIFO) data structure
operations
boolean empty()
int size()
void enqueue(Object ob)
Object dequeue()
Java
has a Stack class
version
of Java we’re using doesn’t have a Queue class
(strange)
but newer versions of Java have a Queue
class
Act out:
·
Push
each candle (“SPOT”) onto a stack S
·
Pop
each candle off, print it, & enqueue it
While (!S.empty()) {
System.out.print(S.peek()); Q.enqueue(S.pop());
}
·
Dequeue and print each letter in the queue
How to implement a Stack ADT
using array or ArrayList
class
Stack {
// fields
private Object [] items;
private int numItems;
or
private ArrayList
s; // better choice
key question:
should
be the top of the stack be the beginning or the end of the list?
What is
the complexity of push(ob) and pop() for each case?
top |
push(ob) |
time |
pop() |
time |
beginning |
s.add(0,ob) |
O(N) |
s.remove(0) |
O(N) |
end |
s.add(ob) |
O(1) |
s.remove(s.size()-1) |
O(1) |
design
decision: last = top of stack
Other methods: constructor, empty, size, peek
Implementation
is straightforward
You try:
write the constructor & push("x") methods
for ArrayList s
if you have
extra time, write for Object [] items
Solution:
ArrayList
s:
// constructor
public Stack() {
s = new ArrayList();
}
// push
public void push (Object ob) {
s.add(ob);
}
Object : items:
// constructor
public Stack() {
items = new Object[initSize];
numItems = 0;
}
// push
public void push (Object ob) {
// expand array if full
items[numItems] =
ob;
numItems ++;
}
Implementing Stack using a linked list
//
fields
private Listnode
items;
private int numItems;
or
private LinkedList
s;
key question
·
Should
the top of the stack be the first or the last item in the linked
list (assuming singly-linked)?
What is
the complexity of push(ob) and pop() for each case?
top |
push(ob) |
time |
pop() |
time |
first item |
s.add(0,ob) |
O(1) |
s.remove(0) |
O(1) |
last item |
s.add(ob) |
O(1) |
s.remove(s.size()-1) |
O(N) |
design decision: first = top of stack
· implementation for LinkedList s is straightforward
·
ArrayList & LinkedList
implementations are efficient,
i.e., O(1) for all
operations
Implementing a Queue using a
Linked List
Q
key question:
which end of the list should be the front of the
queue?
consider the complexity of enqueue(ob)
& dequeue():
front |
enqueue(ob) |
time |
dequeue() |
time |
first item |
add(ob) |
O(1) |
remove(0) |
O(1) |
last item |
add(0,ob) |
O(1) |
remove(size()-1) |
O(N) |
design
decisions
Ž first
in list = front of the queue
keep a pointer to LastNode for enqueue operation
You try
write
fields, constructor & enqueue for LinkedList Q
–
if
you have extra time, write it for linked list called "items",
solutions
for LinkedList Q:
private
LinkedList Q;
public
Queue() {
Q = new LinkedList();
}
public void enqueue(Object ob){
Q.add(0,ob);
}
for
linked list called "items":
private
Listnode items;
private
int numItems;
private Listnode lastNode;
public Queue() {
items = lastNode
= new Listnode(null);
lastNode = items;
numItems = 0;
}
public void enqueue(Object ob){
Listnode tmp
= new Listnode(ob));
lastNode.setNext(tmp);
lastNode = tmp;
numItems++;
}