<<

4.3 Stacks and Queues

1

Data Structures and Data Types Collections

Data types Fundamental data types. • Set of values. • Set of operations (add, remove, if empty) on generic data. • Set of operations on those values. • Intent is when we insert. • Some are built in to Java: int, double, char, String, . . . • item do we remove? are not: Complex, Picture, Charge, Stack, Queue, , . . . • LIFO = "last in first out" Stack. (this lecture) this lecture Data structures. • Remove the item most recently added. • Represent data. • : cafeteria trays, Web surfing. Represent relationships among data. • FIFO = "first in first out" • Some are built in to Java: arrays, . . . Queue. (see text) • Most are not: linked list, circular list, , sparse array, graph, . . . • Remove the item least recently added. • Ex: Registrar's line. this lecture TSP next lecture (assignment 8) Symbol Table. (next lecture) Design challenge for every data : What data structure to use? • Remove item with a given key. • Requirement 1: Space usage. • Ex: Phone book • Requirement 2: usage for data-type methods

3 4 FIFO Queue API

FIFO Queues public class QueueOfStrings QueueOfStrings() create an empty queue int length() size of the queue void put(String item) put a string onto the queue String get() get a string from the queue

it it

was put was get was get the the the the length best best best best 3 of of of

5 6

Queue Client Code Example: Read from input stream into an array

from previous lecture public class WhiteFilter { public static void main(String[] args) Pushdown Stacks { In in = new In(args[0]); String[] words; // Fill words[] with strings from In (stay tuned). while (!StdIn.isEmpty()) { String key = StdIn.readString(); if (search(key, words) != -1) StdOut.println(key); QueueOfStrings q = new QueueOfStrings(); } while (!in.isEmpty()) } q.put(in.readString()); } int N = q.length(); words = new String[N]; for (int i = 0; i < N; i++) words[i] = q.get();

Solves basic problem • Can’t store strings in array until it is created. • Can’t create array without knowing how many strings in input stream. • Can’t know how many strings in input stream without reading them all. • Solution: keep them in a Queue

See text for implementation/applications (after learning about Stacks).

7 8 Stack API Stack Client Example 1: Reverse

public class Reverse { public static void main(String[] args) { StackOfStrings stack = new StackOfStrings(); while (!StdIn.isEmpty()) stack.push(StdIn.readString()); while (!stack.isEmpty()) StdOut.print(stack.pop()); *: we will consider than one implementation StdOut.println(); } } % more tiny.txt it was the best of times

times % java Reverse tiny.txt times of of of times of best the was it of best push best pop best pop best the the the the best stack contents when StdIn is empty was was was was the

it it it it was

it

9 10

Stack Client Example 2: Test Client Stack Client Example 3: Balanced Parentheses

public static void main(String[] args) { StackOfStrings stack = new StackOfStrings(); while (!StdIn.isEmpty()) { String item = StdIn.readString(); ( ( ( a + b ) * d ) + ( e * f ) ) if (item.compareTo("-") != 0) stack.push(item); ( ) else ( ) ( ) System.out.print(stack.pop()); ( ) } push pop System.out.println(); push pop push pop } % more test.txt push pop to be or not to - be - - that - - - is

% java StackOfStrings < test.txt to be not that or be to

not stack contents just before first pop() operation or

be

to

11 12 Stack Client Example 3: Balanced Parentheses Stack: Array Implementation public class Balanced { Array implementation of a stack. public static void main(String[] args) • Use array a[] to store N items on stack. PROBLEM: How big to array? (Stay tuned.) { push StackOfStrings stack = new StackOfStrings(); • push() add new item a[N]. while (!StdIn.isEmpty()) pop() remove item from a[N-1]. { • pop String item = StdIn.readString(); if (item.compareTo("(") == 0) Strawman solution: Make client provide capacity. stack.push(item); public class ArrayStackOfStrings NOTE: This ‘solution’ violates the API! if (item.compareTo(")") == 0) { { private String[] a; if (stack.isEmpty()) private int N = 0; { StdOut.println(“Not balanced”); return; } stack.pop(); public ArrayStackOfStrings(int max) } { a = new String[max]; } } not stack contents after if (!stack.isEmpty()) StdOut.println(“Not balanced”); public boolean isEmpty() 4th push() operation else StdOut.println(“Balanced”); or } { return (N == 0); } } be % java Balanced public void push(String item) ( ( ( a + b ) * d ) + ( e * f ) ) { a[N++] = item; } to N Balanced public String pop() % java Balanced { return a[--N]; } to be or not ( ( a + b ) * d ) + ( e * f ) ) Not balanced } a[0] a[1] a[2] a[3]

13 14

Array Stack: Trace TEQ on Stacks

Q. Can we always insert pop commands (-) to make strings come out sorted?

Ex 1: 6 5 4 3 2 1 - - - - -

push Ex 2: 1 - 2 - 3 - 4 - 5 - 6 -

Ex 3: 4 1 - 3 2 - - - 6 5 - -

pop

15 16 Array Stack: Performance Example: potential stack client

Possible implementation of Java memory management system (sketch) Running time. Push and pop take constant time. ✓ Maintain N stacks stack i: blocks of contiguous 2i byte chunks of memory Memory. Proportional to client-supplied capacity, not number of items. ✗ • • new: pop from stack t, where 2t is smallest block that will hold new object stack t empty? pop from t+1, in half, push 2 blocks on stack t Problem. • garbage collector: periodically finds unused memory blocks How? See COS 226. Original API does not call for capacity (never good to change API) • • and pushes onto appropriate stack. • Client might have multiple stacks • Client might not know what capacity to use (depends on its client) Properties • many stacks • stack size unpredictable . . .

2 4 8 16

Stack implementation without capacity restriction (as in API) is a requirement Challenge. Stack implementation where space use is not fixed ahead of time.

17 18

Sequential vs. Linked Data Structures

Linked Lists Sequential data structure. Put object one next to another. • TOY: consecutive memory cells. • Java: array of objects.

Linked data structure. Include in each object a to the another one. • TOY: link is memory address of next object. • Java: link is reference to next object. addr value addr value C0 "Alice" C0 "Carol"

C1 "Bob" C1 null th Key distinctions. get i element C2 "Carol" C2 - Array: arbitrary access, fixed size. C3 - C3 - • C4 - C4 "Alice" Linked list: sequential access, variable size. • C5 - C5 CA C6 - C6 - get next element C7 - C7 -

C8 - C8 -

C9 - C9 - Linked structures. CA - CA "Bob" CB - CB C0 • Not intuitive, overlooked by naive programmers linked list • Flexible, widely used method for organizing data array

19 20 Singly-linked data structures Linked Lists

From the point of view of a particular object, all of these structures Linked list. look the same: • Simplest linked structure. A recursive data structure. Sequential list (this lecture) Rho • • An item plus a pointer to another linked list (or empty list). • Unwind recursion: linked list is a sequence of items. Tree

Circular list (TSP) Node data type. public class Node { A reference to a String. • private String item; • A reference to another Node. private Node next; }

Confusing point: General case Purpose of data structure is to represent data in a data type but, we also use data types to implement data structures Example: The data type Node acts behind the scenes to implement the linked list data structure. It is not visible to the client. first

Alice Bob Carol

item next Multiply linked structures: many more possibilities! special pointer value null terminates list 21 22

Building a Linked List Traversing a List

Iteration. Idiom for traversing a null-terminated linked list. addr Value Node third = new Node(); third.item = "Carol"; C0 "Carol" third.next = null; C1 null Node x = first; Node second = new Node(); C2 - while (x != null) second.item = "Bob"; C3 - { second.next = third; StdOut.println(x.item); first C4 C4 "Alice" x = x.next; Node first = new Node(); } first.item = "Alice"; second CA C5 CA first.next = second; third C0 C6 - shorthand version C7 - for (Node x = first; x != null; x = x.next) C8 - StdOut.println(x.item); C9 -

CA "Bob"

CB C0 first second third StdOut CC - first

CD - Alice Bob Carol Alice Bob Carol CE - item next item next null CF -

main memory

23 24 Stack Push: Linked List Implementation Stack Pop: Linked List Implementation

first

"of" best the was it first

of best the was it item = first.item;

first second

best the was it second = first; first

of best the was it first = first.next; first second garbage-collected best the was it first = new Node();

first

first second best the was it return item;

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

25 26

Stack: Linked List Implementation Linked List Stack: Trace public class LinkedStackOfStrings { private Node first = null; push

private class Node not stack contents after { 4th push() operation private String item; or in test client private Node next; } be

public boolean isEmpty() to { return first == null; } pop

public void push(String item) { first Node second = first; first = new Node(); not first.item = item; first.next = second; } or

public String pop() be { String item = first.item; to first = first.next; Note difference between first and second: return item; first: an instance variable that retains state } second: a local variable that goes out of scope } 27 28 Linked-List Stack: Performance Stack Data Structures: Tradeoffs

Two data structures to implement the Stack data type. Running time. Push and pop take constant time. ✓

Memory. Always proportional to number of items in stack. ✓ Array. • Every push/pop operation take constant time. • But does not implement API… (must fix max capacity ahead of time).

Linked list. • Every push/pop operation takes constant time. • But… uses extra space and time to deal with references.

Client can evaluate performance tradeoffs to choose among APIs (implicitly choosing among underlying data structures)

29 30

TEQ on List Processing 1 TEQ on List Processing 2

What does the following code do? What does the following code do?

...... Node list = null; Node list = new Node(); while (!StdIn.isEmpty()) list.item = StdIn.readString(); { Node last = list; Node old = list; while (!StdIn.isEmpty()) list = new Node(); { list.item = StdIn.readString(); last.next = new Node(); list.next = old; last = last.next;; } last.item = StdIn.readString(); for (Node t = list; t != null; t = t.next) } StdOut.println(t.item); ......

31 32 Parameterized Data Types

Parameterized Data Types We implemented: StackOfStrings.

We also want: StackOfMemoryBlocks, StackOfURLs, StackOfInts, …

Strawman. Implement a separate stack class for each type. • Rewriting code is tedious and error-prone. • Maintaining -and-pasted code is tedious and error-prone.

33 34

Generics Generic Stack: Linked List Implementation String stack (for reference) public class LinkedStackOfStrings public class Stack Generics. Parameterize stack by a single type. { { private Node first = null; private Node first = null;

private class Node private class Node parameterized { { type name private String item; private Item item; chosen by “Stack of Apples” parameterized type private Node next; private Node next; programmer } }

Stack stack = new Stack(); public boolean isEmpty() public boolean isEmpty() Apple a = new Apple(); { return first == null; } { return first == null; } Orange b = new Orange(); stack.push(a); public void push(String item) public void push(Item item) stack.push(b); // compile-time error { { a = stack.pop(); Node second = first; Node second = first; first = new Node(); first = new Node(); first.item = item; first.item = item; Can’t push an “Orange” first.next = second; first.next = second; sample client onto a “Stack of Apples” } }

public String pop() public Item pop() { { String item = first.item; Item item = first.item; first = first.next; first = first.next; return item; return item; } } } } 35 36 Autoboxing Stack Applications

Generic stack implementation. Real world applications. • Cannot use primitives with parameterized data types • Parsing in a compiler. • Can only substitute a reference type name for a parameterized name. • Java virtual machine. • Undo in a word processor. Wrapper type. • Back button in a Web browser. • Each primitive type has a wrapper reference type. • PostScript language for printers. • Ex: Integer is wrapper type for int. • Implementing function calls in a compiler. • Wrapper type has larger set of operations than primitive type. • Values of wrapper type are objects.

Autoboxing. Automatic cast from primitive type to wrapper type. Autounboxing. Automatic cast from wrapper type to primitive type.

Stack stack = new Stack(); stack.push(17); // Autobox (int -> Integer) int a = stack.pop(); // Auto-unbox (Integer -> int)

37 38

Stack Client 4: Arithmetic Expression Evaluation Arithmetic Expression Evaluation

value stack public class Evaluate Goal. Evaluate infix expressions. operator stack { public static void main(String[] args) { Stack ops = new Stack(); operand operator Stack vals = new Stack(); while (!StdIn.isEmpty()) { Two stack algorithm. [E. . Dijkstra] String s = StdIn.readString(); if (s.equals("(")) ; • Value: push onto the value stack. else if (s.equals("+")) ops.push(s); Operator: push onto the operator stack. else if (s.equals("*")) ops.push(s); • else if (s.equals(")")) • Left parens: ignore. { String op = ops.pop(); • Right parens: pop operator and two values; if (op.equals("+")) push the result of applying that operator vals.push(vals.pop() + vals.pop()); else if (op.equals("*")) to those values onto the operand stack. vals.push(vals.pop() * vals.pop()); } else vals.push(Double.parseDouble(s)); } StdOut.println(vals.pop()); } % java Evaluate } ( 1 + ( ( 2 + 3 ) * ( 4 * 5 ) ) ) 101.0

39 40 Correctness Postfix

Why correct? When algorithm encounters an operator surrounded by two Observation 1. Remarkably, the 2-stack algorithm computes the same value values 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 * ) * ) + )

So it's as if the original input were: Observation 2. Now all of the parentheses are redundant! ( 1 + ( 5 * ( 4 * 5 ) ) )

Repeating the argument: 1 2 3 + 4 5 * * +

( 1 + ( 5 * 20 ) ) ( 1 + 100 ) 101 Bottom line. Postfix or "reverse Polish" notation. Jan Lukasiewicz

Extensions. More ops, precedence order, associativity, whitespace.

1 + (2 - 3 - 4) * 5 * sqrt(6*6 + 7*7)

41 42

Real-World Stack Application: PostScript Context/Definitions/Summary

20 drawing PostScript (Warnock-Geschke, 1980s). A turtle with a stack. Interpreter. PostScript code 5 postfix program code Takes a program as input 100 100 moveto • 1 • 100 300 lineto 300 300 lineto Interpreter • add commands to drive virtual graphics machine • Does what that program would do. 300 100 lineto • add loops, conditionals, functions, types • Simulates a virtual machine. stroke

PostScript code Compiler. TOY code Java code 7102 units are points Takes a program as input 7203 100 100 moveto • a = 2 + 3 Compiler (72 per inch) 1312 100 300 lineto Produces a program as output. 9330 define a path • 300 300 lineto Produces code for a (real) machine. 300 100 lineto • stroke draw the path TOY is our proxy for a real machine Virtual machines you have used • LFSR Data Type and Virtual Machine are the same thing! • Stack Simple virtual machine, but not a toy. • Set of values = machine state. • TOY Easy to specify published page. Operations on values = machine operations. • PostScript • • • Java Virtual Machine • Easy to implement on various specific printers (another stack machine) • Revolutionized world of publishing. Data Structure. • Virtually all printed material is PostScript. • Represent data and relationships among data in a data type. array, linked list, compound, multiple links per node 43 • 44