Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
0% found this document useful (0 votes)
44 views

02 Stack Queue

The document discusses stacks and queues, which are fundamental data structures. It defines stacks as last-in, first-out (LIFO) structures where the most recently added item is removed first. Queues are first-in, first-out (FIFO) structures where the oldest item is removed first. The document provides examples of stack and queue operations like push, pop, enqueue, and dequeue. It also discusses implementations of stacks using linked lists and arrays and the benefits of separating interfaces from implementations to create reusable and modular code.

Uploaded by

varyk
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
44 views

02 Stack Queue

The document discusses stacks and queues, which are fundamental data structures. It defines stacks as last-in, first-out (LIFO) structures where the most recently added item is removed first. Queues are first-in, first-out (FIFO) structures where the oldest item is removed first. The document provides examples of stack and queue operations like push, pop, enqueue, and dequeue. It also discusses implementations of stacks using linked lists and arrays and the benefits of separating interfaces from implementations to create reusable and modular code.

Uploaded by

varyk
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 12

Stacks and Queues

Fundamental data types.


• Values: sets of objects

Stacks and Queues •
Operations: insert, remove, test if empty.
Intent is clear when we insert.
• Which item do we remove?
LIFO = "last in first out"

Stack.
• Remove the item most recently added.
! stacks • Analogy: cafeteria trays, Web surfing.
FIFO = "first in first out"
! dynamic resizing Queue.
! queues • Remove the item least recently added.
! generics • Analogy: Registrar's line.
! applications push

pop

enqueue dequeue

1 2

Client, Implementation, Interface Client, Implementation, Interface

Separate interface and implementation so as to: Benefits.


• Build layers of abstraction. • Client can't know details of implementation !
• Reuse software. client has many implementation from which to choose.
• Ex: stack, queue, symbol table. • Implementation can't know details of client needs !
many clients can re-use the same implementation.
• Design: creates modular, re-usable libraries.
• Performance: use optimized implementation where it matters.

Interface: description of data type, basic operations. Interface: description of data type, basic operations.
Client: program using operations defined in interface. Client: program using operations defined in interface.
Implementation: actual code implementing operations. Implementation: actual code implementing operations.

3 4
Stacks

Stack operations.
• push() Insert a new item onto stack.
• pop() Remove and return the item most recently added.
• isEmpty() Is the stack empty? push

pop

public static void main(String[] args)


{
StackOfStrings stack = new StackOfStrings();
! stacks while(!StdIn.isEmpty())

! dynamic resizing
{
String s = StdIn.readString();
! queues stack.push(s);

! generics
}
while(!stack.isEmpty())
! applications {
String s = stack.pop();
StdOut.println(s);
}
}
a sample stack client
5 6

Stack pop: Linked-list implementation Stack push: Linked-list implementation

first

best the was it


first

of best the was it item = first.item; first second

first
best the was it second = first;

best the was it first = first.next;


first second

best the was it first = new Node();


first

best the was it return item;


first second

of best the was it


first.item = item;
first.next = second;

7 8
Stack: Linked-list implementation Stack: Array implementation

public class StackOfStrings


{ Array implementation of a stack.
private Node first = null;
• Use array s[] to store N items on stack.
private class Node
{ • push() add new item at s[N].
String item;
Node next;
"inner class" • pop() remove item from s[N-1].
}
public boolean isEmpty()
{ return first == null; } Error conditions?
public void push(String item) Example: pop() an empty stack
{
Node second = first; s[] it was the best
first = new Node(); COS 217: bulletproof the code
first.item = item; COS 226: first find the code we want to use 0 1 2 3 4 5 6 7 8 9
first.next = second;
} N

public String pop()


{
String item = first.item;
first = first.next;
return item;
}
}

9 10

Stack: Array implementation

public class StackOfStrings


{
private String[] s;
private int N = 0;

public StringStack(int capacity)


{ s = new String[capacity]; }

public boolean isEmpty()


{ return N == 0; }

public void push(String item)


{ s[N++] = item; } ! stacks
public String pop()
{
! dynamic resizing
String item = s[N-1];
s[N-1] = null;
avoid loitering
(garbage collector only reclaims memory
! queues
N--;
return item;
if no outstanding references) ! generics
} ! applications
}

11 12
Stack array implementation: Dynamic resizing Stack array implementation: Dynamic resizing

Q. How to grow array when capacity reached? Q. How to grow array?


Q. How to shrink array (else it stays big even when stack is small)? A. Use repeated doubling:
if array is full, create a new array of twice the size, and copy items
First try:
• push(): increase size of s[] by 1 no-argument
public StackOfStrings()


{ this(8); }
pop() : decrease size of s[] by 1 constructor
public void push(String item)
{
Too expensive if (N >= s.length) resize();
• Need to copy all of the elements to a new array. s[N++] = item;


}
Inserting N elements: time proportional to 1 + 2 + … + N " N2/2.
private void resize(int max)
{
create new array
infeasible for large N copy items to it
String[] dup = new String[max];
for (int i = 0; i < N; i++)
dup[i] = s[i];
s = dup;
}

Need to guarantee that array resizing happens infrequently Consequence. Inserting N items takes time proportional to N (not N2).
13 8 + 16 + … + N/4 + N/2 + N " 2N 14

Stack array implementation: Dynamic resizing Stack Implementations: Array vs. Linked List

Q. How (and when) to shrink array?


Stack implementation tradeoffs. Can implement with either array or
How: create a new array of half the size, and copy items. linked list, and client can use interchangeably. Which is better?
When (first try): array is half full?
No, causes thrashing Array.
(push-pop-push-pop-... sequence: time proportional to N for each op)
• Most operations take constant time.
When (solution): array is 1/4 full (then new array is half full). • Expensive doubling operation every once in a while.
• Any sequence of N operations (starting from empty stack)
public String pop(String item) takes time proportional to N. "amortized" bound
{
String item = s[--N]; Not a.length/2
sa[N] = null; to avoid thrashing Linked list.
if (N == s.length/4)
resize(s.length/2); • Grows and shrinks gracefully.
return item; • Every operation takes constant time.
}
• Every operation uses extra space and time to deal with references.

Consequences. Bottom line: tossup for stacks


• any sequence of N ops takes time proportional to N but differences are significant when other operations are added
• array is always between 25% and 100% full 15 16
Stack implementations: Array vs. Linked list

Which implementation is more convenient?

array? linked list?

return count of elements in stack

remove the kth most recently added


! stacks
! dynamic resizing
sample a random element ! queues
! generics
! applications

17 18

Queues Dequeue: Linked List Implementation

Queue operations.
• enqueue() Insert a new item onto queue. first last

• dequeue() Delete and return the item least recently added.


• isEmpty() Is the queue empty?
it was the best of item = first.item;

first last

public static void main(String[] args) was the best of first = first.next;
{
QueueOfStrings q = new QueueOfStrings();
q.enqueue("Vertigo"); last
first
q.enqueue("Just Lose It");
q.enqueue("Pieces of Me");
was the best of return item;
q.enqueue("Pieces of Me");
System.out.println(q.dequeue());
q.enqueue("Drop It Like It's Hot");

while(!q.isEmpty()
System.out.println(q.dequeue());
} Aside:
dequeue (pronounced “DQ”) means “remove from a queue”
deque (pronounced “deck”) is a data structure (see PA 1)
19 20
Enqueue: Linked List Implementation Queue: Linked List Implementation

public class QueueOfStrings


{
first last
private Node first;
private Node last;

it was the best private class Node


{ String item; Node next; }

first last x public boolean isEmpty()


{ return first == null; }
x = new Node();
it was the best of x.item = item; public void enqueue(String item)
x.next = null; {
Node x = new Node();
first last x
x.item = item;
x.next = null;
if (isEmpty()) { first = x; last = x; }
it was the best of last.next = x; else { last.next = x; last = x; }
}

first last x public String dequeue()


{
String item = first.item;
it was the best of last = x; first = first.next;
return item;
}
}
21 22

Queue: Array implementation

Array implementation of a queue.


• Use array q[] to store items on queue.
• enqueue(): add new object at q[tail].
• dequeue(): remove object from q[head].
• Update head and tail modulo the capacity.

q[] the best of times


! stacks
0 1 2 3 4 5 6 7 8 9
! dynamic resizing
head tail capacity = 10 ! queues
! generics
! applications
[details: good exercise or exam question]

23 24
Generics (parameterized data types) Stack of Objects

We implemented: StackOfStrings, QueueOfStrings. We implemented: StackOfStrings, QueueOfStrings.

We also want: StackOfURLs, QueueOfCustomers, etc? We also want: StackOfURLs, QueueOfCustomers, etc?

Attempt 1. Implement a separate stack class for each type. Attempt 2. Implement a stack with items of type Object.
• Rewriting code is tedious and error-prone. • Casting is required in client.
• Maintaining cut-and-pasted code is tedious and error-prone. • Casting is error-prone: run-time error if types mismatch.

@#$*! most reasonable approach until Java 1.5 [hence, used in AlgsJava]

Stack s = new Stack();


Apple a = new Apple();
Orange b = new Orange();
s.push(a);
s.push(b); run-time error
a = (Apple) (s.pop());

25 26

Generics Generic Stack: Linked List Implementation

Generics. Parameterize stack by a single type.



public class StackOfStrings public class Stack<Item>
Avoid casting in both client and implementation. { {
• Discover type mismatch errors at compile-time instead of run-time. private Node first = null;
private class Node
private Node first = null;
private class Node
{ { Generic type name
parameter
String item; Item item;
Node next; Node next;
} }
Stack<Apple> s = new Stack<Apple>(); public boolean isEmpty() public boolean isEmpty()
Apple a = new Apple(); { return first == null; } { return first == null; }
Orange b = new Orange();
public void push(String item) public void push(Item item)
s.push(a); { {
s.push(b); compile-time error Node second = first; Node second = first;
a = s.pop(); first = new Node(); first = new Node();
first.item = item; first.item = item;
no cast needed in client first.next = second; first.next = second;
} }
public String pop() public Item pop()
Guiding principles. { {

• Welcome compile-time errors String item = first.item;


first = first.next;
Item item = first.item;
first = first.next;
• Avoid run-time errors
}
return item;
}
return item;

Why? } }
27 28
Generic stack: array implementation Generic stack: array implementation

The way it should be. The way it is: an ugly cast in the implementation.

public class Stack<Item> public class StackOfStrings public class Stack<Item>


{ { {
private Item[] s; private String[] s; private Item[] s;
private int N = 0; private int N = 0; private int N = 0;

public Stack(int cap) public StackOfStrings(int cap) public Stack(int cap)


{ s = new Item[cap]; } { s = new String[cap]; } { s = (Item[]) new Object[cap]; } the ugly cast

public boolean isEmpty() public boolean isEmpty() public boolean isEmpty()


{ return N == 0; } { return N == 0; } { return N == 0; }

public void push(Item item) public void push(String item) public void push(Item item)
{ s[N++] = item; } { s[N++] = item; } { s[N++] = item; }

public String pop() public String pop() public String pop()


{ { {
Item item = s[N-1]; String item = s[N-1]; Item item = s[N-1];
s[N-1] = null; s[N-1] = null; s[N-1] = null;
N--; N--; N--;
return item; return item; return item;
} } }

} } }

@#$*! generic array creation not allowed in Java


Number of casts in good code: 0
29 30

Generic data types: autoboxing

Generic stack implementation is object-based.

What to do about primitive types?

Wrapper type.
•Each primitive type has a wrapper object type.
•Ex: Integer is wrapper type for int.

Autoboxing. Automatic cast between a primitive type and its wrapper. ! stacks
Syntactic sugar. Behind-the-scenes casting.
! dynamic resizing
! queues
Stack<Integer> s = new Stack<Integer>(); ! generics
! applications
s.push(17); // s.push(new Integer(17));
int a = s.pop(); // int a = ((int) s.pop()).intValue();

Bottom line: Client code can use generic stack for any type of data
31 32
Stack Applications Function Calls

Real world applications. How a compiler implements functions.


• Parsing in a compiler. • Function call: push local environment and return address.
• Java virtual machine. • Return: pop return address and local environment.
• Undo in a word processor.
• Back button in a Web browser. Recursive function. Function that calls itself.
• PostScript language for printers. Note. Can always use an explicit stack to remove recursion.
• Implementing function calls in a compiler.

gcd (216, 192)

static int gcd(int p, int q) {


if (q == 0) return gcdp;
(192, 24)
p = 216, q = 192
else return gcd(q, p % q);
}
static int gcd(int p, int q) {
if (q == 0) returngcdp;(24, 0)
p = 192, q = 24
else return gcd(q, p % q);
}
static int gcd(int p, int q) {
if (q == 0) return p;
p = 24, q = 0
else return gcd(q, p % q);
}
33 34

Arithmetic Expression Evaluation Arithmetic Expression Evaluation

Goal. Evaluate infix expressions.


value stack public class Evaluate {
operator stack
public static void main(String[] args) {
operand operator Stack<String> ops = new Stack<String>();
Stack<Double> vals = new Stack<Double>();
while (!StdIn.isEmpty()) {
Two-stack algorithm. [E. W. Dijkstra] String s = StdIn.readString();

• Value: push onto the value stack. if (s.equals("(")) ;


else if (s.equals("+")) ops.push(s);
Operator: push onto the operator stack. else if (s.equals("*")) ops.push(s);
• Left parens: ignore. else if (s.equals(")")) {

• Right parens: pop operator and two values; String op = ops.pop();


if (op.equals("+")) vals.push(vals.pop() + vals.pop());
push the result of applying that operator
else if (op.equals("*")) vals.push(vals.pop() * vals.pop());
to those values onto the operand stack. }
else vals.push(Double.parseDouble(s));
}
StdOut.println(vals.pop()); % java Evaluate
Context. An interpreter! } ( 1 + ( ( 2 + 3 ) * ( 4 * 5 ) ) )
101.0
}

35 Note: Old books have two-pass algorithm because generics were not available! 36
Correctness Stack-based programming languages

Why correct? Observation 1.


When algorithm encounters an operator surrounded by two values Remarkably, the 2-stack algorithm computes the same value
within parentheses, it leaves the result on the value stack. if the operator occurs after the two values.

( 1 + ( ( 2 + 3 ) * ( 4 * 5 ) ) )
( 1 ( ( 2 3 + ) ( 4 5 * ) * ) + )
as if the original input were:
Observation 2.
( 1 + ( 5 * ( 4 * 5 ) ) )
All of the parentheses are redundant!
Repeating the argument:
1 2 3 + 4 5 * * +
( 1 + ( 5 * 20 ) )
( 1 + 100 ) Jan Lukasiewicz
101

Bottom line. Postfix or "reverse Polish" notation.

Extensions. More ops, precedence order, associativity.


Applications. Postscript, Forth, calculators, Java virtual machine, …
1 + (2 - 3 - 4) * 5 * sqrt(6 + 7)

37 38

Stack-based programming languages: PostScript Stack-based programming languages: PostScript

Page description language Data types


• explicit stack • basic: integer, floating point, boolean, ...
• full computational model • graphics: font, path, ....
• graphics engine • full set of built-in operators

Basics Text and strings like System.out.print()

• %!: “I am a PostScript program” • full font support


• literal: “push me on the stack” • show (display a string, using current font)
• function calls take args from stack • cvs (convert anything to a string)
Square root of 2:
1.4142

• turtle graphics built in


like toString()

%!
72 72 moveto
a PostScript program %!
0 72 rlineto
/Helvetica-Bold findfont 16 scalefont setfont
72 0 rlineto
72 168 moveto
0 -72 rlineto
(Square root of 2:) show
-72 0 rlineto
72 144 moveto
2 setlinewidth
2 sqrt 10 string cvs show
stroke

39 40
Stack-based programming languages: PostScript Stack-based programming languages: PostScript

Variables (and functions) for loop


• identifiers start with / • “from, increment, to” on stack
• def operator associates id with value • loop body in braces
• braces • for operator
• args on stack
%! 1 1 20
function definition /box { 19 mul dup 2 add moveto 72 box }
{ for
/sz exch def
0 sz rlineto
sz 0 rlineto
0 sz neg rlineto
sz neg 0 rlineto if-else
} def
• boolean on stack
• alternatives in braces

72 144 moveto
72 box if operator
function calls 288 288 moveto
144 box
... (hundreds of operators)
2 setlinewidth
stroke
41 42

Stack-based programming languages: PostScript Queue applications

An application: all figures in Algorithms in Java Familiar applications.


• iTunes playlist.
• Data buffers (iPod, TiVo).

%!
72 72 translate Asynchronous data transfer (file IO, pipes, sockets).
/kochR • Dispensing requests on a shared resource (printer, processor).
{
2 copy ge { dup 0 rlineto }
{
Simulations of the real world.
3 div • Traffic analysis.

2 copy kochR 60 rotate
2 copy kochR -120 rotate Waiting times of customers at call center.
2 copy kochR 60 rotate
2 copy kochR
• Determining number of cashiers to have at a supermarket.
} ifelse
pop pop
} def See page 218

0 0 moveto 81 243 kochR


0 81 moveto 27 243 kochR
0 162 moveto 9 243 kochR
0 243 moveto 1 243 kochR
stroke

43 44
M/D/1 queuing model M/D/1 queuing model: example

M/D/1 queue.
• Customers are serviced at fixed rate of µ per minute.
• Customers arrive according to Poisson process at rate of # per minute.
inter-arrival time has exponential distribution

Pr[X " x] = 1# e# $x

Arrival rate # Departure rate µ

Infinite queue Server

Q. What is average wait time W of a customer?


Q. What is average number of customers L in system?

45 46

M/D/1 queuing model: experiments and analysis M/D/1 queuing model: event-based simulation

Observation. public class MD1Queue


{
As service rate µ approaches arrival rate #, service goes to h***. public static void main(String[] args)
{
double lambda = Double.parseDouble(args[0]); // arrival rate
double mu = Double.parseDouble(args[1]); // service rate
Histogram hist = new Histogram(60);
Queue<Double> q = new Queue<Double>();
double nextArrival = StdRandom.exp(lambda);
double nextService = 1/mu;
while (true)
{
while (nextArrival < nextService)
{
q.enqueue(nextArrival);
nextArrival += StdRandom.exp(lambda);
}
double wait = nextService - q.dequeue();
hist.addDataPoint(Math.min(60, (int) (wait)));
if (!q.isEmpty())
nextService = nextArrival + 1/mu;
Little’s Law
else
nextService = nextService + 1/mu;
" 1
Queueing theory (see ORFE 309). W = + , L = " W }
2 µ (µ # " ) µ }
}
wait time W and queue length L approach infinity as service rate approaches arrival rate
47 48

You might also like