Survey
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
Algorithms Stacks and queues R OBERT S EDGEWICK | K EVIN W AYNE Fundamental data types. ・Value: collection of objects. ・Operations: insert, remove, iterate, test if empty. ・Intent is clear when we insert. ・Which item do we remove? 1.3 B AGS , QUEUES, AND S TACKS ‣ stacks stack push ‣ resizing arrays Algorithms F O U R T H E D I T I O N R OBERT S EDGEWICK | K EVIN W AYNE http://algs4.cs.princeton.edu pop ‣ queues queue dequeue enqueue ‣ generics ‣ iterators ‣ applications Stack. Examine the item most recently added. LIFO = "last in first out" Queue. Examine the item least recently added. FIFO = "first in first out" 2 Client, implementation, interface Separate interface and implementation. Ex: stack, queue, bag, priority queue, symbol table, union-find, .… Benefits. ・Client can't know details of implementation 1.3 B AGS, Q UEUES, AND STACKS ⇒ client has many implementation from which to choose. ・Implementation can't know details of client needs ‣ stacks ⇒ many clients can re-use the same implementation. ・ ・Performance: ‣ resizing arrays Design: creates modular, reusable libraries. Algorithms use optimized implementation where it matters. R OBERT S EDGEWICK | K EVIN W AYNE Client: program using operations defined in interface. http://algs4.cs.princeton.edu Implementation: actual code implementing operations. Interface: description of data type, basic operations. 3 ‣ queues ‣ generics ‣ iterators ‣ applications Stack API Stack test client Warmup API. Stack of strings data type. Read strings from standard input. push ・If string equals "-", pop string from stack and print. ・Otherwise, push string onto stack. pop push pop public class StackOfStrings public static void main(String[] args) { StackOfStrings stack = new StackOfStrings(); while (!StdIn.isEmpty()) { String s = StdIn.readString(); create an empty stack StackOfStrings() insert a new string onto stack void push(String item) remove and return the string most recently added String pop() if (s.equals("-")) StdOut.print(stack.pop()); else stack.push(s); is the stack empty? boolean isEmpty() } number of strings on the stack int size() } % more tobe.txt to be or not to - be - - that - - - is % java StackOfStrings < tobe.txt to be not that or be Warmup client. Reverse sequence of strings from standard input. 5 Stack: linked-list representation 6 Stack pop: linked-list implementation Maintain pointer to first node in a linked list; insert/remove from front. StdIn StdOut be be insert at front of linked list first not not to to remove from front of linked list to - that not be be - String item = first.item; be not to delete first node null or or - save item to return to null to not be or not or not or inner class to null be or be or be private class Node { String item; Node next; to null be } to null first = first.next; first or to null to null first or to null be be be to null return saved item return item; to null or be that or to null be Removing the first node in a linked list to null 7 8 Stack push: linked-list implementation Stack: linked-list implementation in Java public class LinkedStackOfStrings { private Node first = null; save a link to the list Node oldfirst = first; oldfirst first inner class or be private class Node { String item; Node next; } to null create a new node for the beginning public boolean isEmpty() { return first == null; first = new Node(); private class Node { String item; Node next; } oldfirst first or be to null first.item = "not"; first.next = oldfirst; not or be } public void push(String item) { Node oldfirst = first; first = new Node(); first.item = item; first.next = oldfirst; } set the instance variables in the new node first private inner class (access modifiers don't matter) public String pop() { String item = first.item; first = first.next; return item; } to null } Inserting a new node at the beginning of a linked list 9 10 Stack: linked-list implementation performance Stack: array implementation Proposition. Every operation takes constant time in the worst case. Array implementation of a stack. Proposition. A stack with N items uses ~ 40 N bytes. ・Use array s[] to store N items on stack. ・push(): add new item at s[N]. ・pop(): remove item from s[N-1]. node object (inner class) public class Node { String item; inner class Node next; ... private class Node } { String item; Node next; } 40 bytes object overhead 16 bytes (object overhead) extra overhead 8 bytes (inner class extra overhead) s[] 8 bytes (reference to String) item references next 8 bytes (reference to Node) to be or not to be null null null null 0 1 2 3 4 5 6 7 8 9 N 40 bytes per stack node capacity = 10 Remark. This accounts for the memory for the stack (but not the memory for strings themselves, which the client owns). Defect. Stack overflows when N exceeds capacity. [stay tuned] 11 12 Stack: array implementation Stack considerations Overflow and underflow. public class FixedCapacityStackOfStrings { private String[] s; private int N = 0; ・Underflow: throw exception if pop from an empty stack. ・Overflow: use resizing array for array implementation. [stay tuned] a cheat (stay tuned) Null items. We allow null items to be inserted. public FixedCapacityStackOfStrings(int capacity) { s = new String[capacity]; } Loitering. Holding a reference to an object when it is no longer needed. public boolean isEmpty() { return N == 0; } public String pop() { return s[--N]; } public void push(String item) { s[N++] = item; } loitering public String pop() { return s[--N]; } use to index into array; then increment N } public String pop() { String item = s[--N]; s[N] = null; return item; } this version avoids "loitering": garbage collector can reclaim memory only if no outstanding references decrement N; then use to index into array 13 14 Stack: resizing-array implementation Problem. Requiring client to provide capacity does not implement API! Q. How to grow and shrink array? First try. 1.3 B AGS, Q UEUES, AND S TACKS ・push(): increase size of array s[] by 1. ・pop(): decrease size of array s[] by 1. ‣ stacks ‣ resizing arrays Algorithms R OBERT S EDGEWICK | K EVIN W AYNE http://algs4.cs.princeton.edu ‣ queues ‣ generics Too expensive. ・Need to copy all items to a new array. ・Inserting first N items takes time proportional to 1 + 2 + … + N ~ ‣ iterators N 2 / 2. infeasible for large N ‣ applications Challenge. Ensure that array resizing happens infrequently. 16 Stack: resizing-array implementation Stack: amortized cost of adding to a stack "repeated doubling" Q. How to grow array? Cost of inserting first N items. N + (2 + 4 + 8 + … + N) ~ 3N. A. If array is full, create a new array of twice the size, and copy items. 1 array access per push k array accesses to double to size k (ignoring cost to create new array) public ResizingArrayStackOfStrings() { s = new String[1]; } public void push(String item) { if (N == s.length) resize(2 * s.length); s[N++] = item; } cost (array accesses) 128 private void resize(int capacity) { String[] copy = new String[capacity]; for (int i = 0; i < N; i++) copy[i] = s[i]; s = copy; } one gray dot for each operation 64 128 red dots give cumulative average 3 0 see next slide number of push() operations 0 128 Amortized cost of adding to a Stack Consequence. Inserting first N items takes time proportional to N (not N 2 ). 17 18 Stack: resizing-array implementation Stack: resizing-array implementation Q. How to shrink array? Q. How to shrink array? First try. Efficient solution. ・ ・pop(): ・push(): ・pop(): push(): double size of array s[] when array is full. halve size of array s[] when array is one-half full. Too expensive in worst case. ・ ・Each operation takes time proportional to N. to be or not N = 4 to be or not N = 5 to be or not N = 4 to be or not halve size of array s[] when array is one-quarter full. public String pop() { Consider push-pop-push-pop-… sequence when array is full. N = 5 double size of array s[] when array is full. String item = s[--N]; s[N] = null; if (N > 0 && N == s.length/4) resize(s.length/2); return item; to null null null to null null null } Invariant. Array is between 25% and 100% full. 19 20 Stack: resizing-array implementation trace Stack resizing-array implementation: performance Amortized analysis. Average running time per operation over push() pop() N a.length 0 1 2 3 4 5 6 7 Proposition. Starting from an empty stack, any sequence of M push and 0 1 null to 1 1 to be 2 2 to be or 3 4 to be or null not 4 4 to be or not to a worst-case sequence of operations. a[] pop operations takes time proportional to M. 5 8 to be or not to null null null to 4 5 8 8 to to be be or or not not null be null null null null null null - be 4 8 to be or not null null null null - not 3 8 to be or null null null null null be that 4 8 to be or that null null null null - that 3 8 to be or null null null null null - or 2 4 to be null null - be 1 2 to null 2 2 to is is best worst amortized construct 1 1 1 push 1 N 1 pop 1 N 1 size 1 1 1 doubling and halving operations Trace of array resizing during a sequence of push() and pop() operations order of growth of running time for resizing stack with N items 21 22 Stack resizing-array implementation: memory usage Stack implementations: resizing array vs. linked list Proposition. Uses between ~ 8 N and ~ 32 N bytes to represent a stack Tradeoffs. Can implement a stack with either resizing array or linked list; with N items. client can use Nodeinterchangeably. oldfirst = first; Which one is better? save a link to the list ・~ 8 N when full. ・~ 32 N when one-quarter full. public class ResizingArrayStackOfStrings { private String[] s; private int N = 0; … } oldfirst Linked-list implementation. first or 8 24 8 4 bytes bytes bytes bytes be ・Every operation takes constant time in the worst case. extra time and space to deal with the links. ・Usescreate a new node for the beginning (reference to array) (array overhead) × array size (int) to null first = new Node(); Resizing-array implementation. oldfirst ・Every operation takes constant amortized time. ・Less wasted space. 4 bytes (padding) first or be to null set the instance variables in the new node N = 4 to= "not"; be or first.item first.next = oldfirst; first Remark. This accounts for the memory for the stack (but not the memory for strings themselves, which the client owns). 23 not or not null be null null null to null Inserting a new node at the beginning of a linked list 24 Queue API enqueue public class QueueOfStrings create an empty queue QueueOfStrings() 1.3 B AGS , QUEUES, AND S TACKS void enqueue(String item) ‣ stacks is the queue empty? boolean isEmpty() ‣ queues Algorithms remove and return the string least recently added String dequeue() ‣ resizing arrays number of strings on the queue int size() ‣ generics insert a new string onto queue ‣ iterators R OBERT S EDGEWICK | K EVIN W AYNE dequeue ‣ applications http://algs4.cs.princeton.edu 26 Queue: linked-list representation Queue dequeue: linked-list implementation Maintain pointer to first and last nodes in a linked list; save item to return insert/remove from opposite ends. StdIn StdOut to to null be to first to not to to to remove from front of linked list to - - be be be be or delete first node first = first.next; be null or - String item = first.item; or not not be be be or or not to inner class last or or not not to be null private class Node { String item; Node next; insert at end of linked list or null not null not to be or null first last to be } or null to null return saved item to null to last first return item; be null Removing the first node in a linked list be null Remark. Identical code to linked-list stack pop(). 27 28 Queue enqueue: linked-list implementation Queue: linked-list implementation in Java save a link to the last node public class LinkedQueueOfStrings { private Node first, last; Node oldlast = last; oldlast private class Node { /* same as in StackOfStrings */ last first to be or null public boolean isEmpty() { return first == null; create a new node for the end inner class oldlast first to be last or null } public void enqueue(String item) { Node oldlast = last; last = new Node(); last.item = item; last.next = null; if (isEmpty()) first = last; else oldlast.next = last; } last = new Node(); last.item = "not"; private class Node { String item; Node next; } } not null special cases for empty queue link the new node to the end of the list public String dequeue() { String item = first.item; first = first.next; if (isEmpty()) last = null; return item; } oldlast.next = last; oldlast first to be last or not null } Inserting a new node at the end of a linked list 29 30 Queue: resizing array implementation Array implementation of a queue. ・Use array q[] to store items in queue. ・enqueue(): add new item at q[tail]. ・dequeue(): remove item from q[head]. ・Update head and tail modulo the capacity. ・Add resizing array. 1.3 B AGS, Q UEUES, AND STACKS ‣ stacks ‣ resizing arrays q[] null null the best of times null null null null 0 1 2 3 4 5 6 7 8 9 head tail Algorithms capacity = 10 R OBERT S EDGEWICK | K EVIN W AYNE http://algs4.cs.princeton.edu Q. How to resize? 31 ‣ queues ‣ generics ‣ iterators ‣ applications Parameterized stack Parameterized stack We implemented: StackOfStrings. We implemented: StackOfStrings. We also want: StackOfURLs, StackOfInts, StackOfVans, …. We also want: StackOfURLs, StackOfInts, StackOfVans, …. 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. ・Maintaining cut-and-pasted code is tedious and error-prone. ・Casting is required in client. ・Casting is error-prone: run-time error if types mismatch. StackOfObjects s = new StackOfObjects(); @#$*! most reasonable approach until Java 1.5. Apple a = new Apple(); Orange b = new Orange(); s.push(a); s.push(b); a = (Apple) (s.pop()); run-time error 33 Parameterized stack 34 Generic stack: linked-list implementation We implemented: StackOfStrings. public class LinkedStackOfStrings { private Node first = null; We also want: StackOfURLs, StackOfInts, StackOfVans, …. private class Node { String item; Node next; } Attempt 3. Java generics. ・Avoid casting in client. ・Discover type mismatch errors at compile-time instead of run-time. public boolean isEmpty() { return first == null; type parameter Stack<Apple> s = new Stack<Apple>(); Apple a = new Apple(); Orange b = new Orange(); s.push(a); s.push(b); public class Stack<Item> { private Node first = null; compile-time error a = s.pop(); } private class Node { Item item; Node next; } public boolean isEmpty() { return first == null; } generic type name } public void push(String item) { Node oldfirst = first; first = new Node(); first.item = item; first.next = oldfirst; } public void push(Item item) { Node oldfirst = first; first = new Node(); first.item = item; first.next = oldfirst; } public String pop() { String item = first.item; first = first.next; return item; } public Item pop() { Item item = first.item; first = first.next; return item; } } Guiding principles. Welcome compile-time errors; avoid run-time errors. 35 36 Generic stack: array implementation Generic stack: array implementation the way it should be public class FixedCapacityStackOfStrings { private String[] s; private int N = 0; the way it is public class FixedCapacityStack<Item> { private Item[] s; private int N = 0; public class FixedCapacityStackOfStrings { private String[] s; private int N = 0; public class FixedCapacityStack<Item> { private Item[] s; private int N = 0; public ..StackOfStrings(int capacity) { s = new String[capacity]; } public FixedCapacityStack(int capacity) { s = new Item[capacity]; } public ..StackOfStrings(int capacity) { s = new String[capacity]; } public FixedCapacityStack(int capacity) { s = (Item[]) new Object[capacity]; } public boolean isEmpty() { return N == 0; } public boolean isEmpty() { return N == 0; } public boolean isEmpty() { return N == 0; } public boolean isEmpty() { return N == 0; } public void push(String item) { s[N++] = item; } public void push(Item item) { s[N++] = item; } public void push(String item) { s[N++] = item; } public void push(Item item) { s[N++] = item; } public String pop() { return s[--N]; } public Item pop() { return s[--N]; public String pop() { return s[--N]; } public Item pop() { return s[--N]; } } } } } } @#$*! generic array creation not allowed in Java the ugly cast 37 Unchecked cast 38 Generic data types: autoboxing Q. What to do about primitive types? Wrapper type. % javac FixedCapacityStack.java Note: FixedCapacityStack.java uses unchecked or unsafe operations. Note: Recompile with -Xlint:unchecked for details. ・Each primitive type has a wrapper object type. ・Ex: Integer is wrapper type for int. % javac -Xlint:unchecked FixedCapacityStack.java FixedCapacityStack.java:26: warning: [unchecked] unchecked cast found : java.lang.Object[] required: Item[] a = (Item[]) new Object[capacity]; ^ 1 warning Autoboxing. Automatic cast between a primitive type and its wrapper. Stack<Integer> s = new Stack<Integer>(); s.push(17); // s.push(Integer.valueOf(17)); int a = s.pop(); // int a = s.pop().intValue(); Bottom line. Client code can use generic stack for any type of data. 39 40 Iteration Design challenge. Support iteration over stack items by client, without revealing the internal representation of the stack. i 1.3 B AGS , QUEUES, AND S TACKS s[] ‣ stacks ‣ resizing arrays Algorithms R OBERT S EDGEWICK | K EVIN W AYNE http://algs4.cs.princeton.edu N it was the best of times null null null null 0 1 2 3 4 5 6 7 8 9 first current ‣ queues of times ‣ generics best the was null it ‣ iterators ‣ applications Java solution. Make stack implement the java.lang.Iterable interface. 42 Iterators Stack iterator: linked-list implementation Iterable interface Q. What is an Iterable ? A. Has a method that returns an Iterator. import java.util.Iterator; public interface Iterable<Item> { Iterator<Item> iterator(); } public class Stack<Item> implements Iterable<Item> { ... public Iterator<Item> iterator() { return new ListIterator(); } Q. What is an Iterator ? Iterator interface private class ListIterator implements Iterator<Item> { private Node current = first; A. Has methods hasNext() and next(). Q. Why make data structures Iterable ? A. Java supports elegant client code. “foreach” statement (shorthand) for (String s : stack) StdOut.println(s); public interface Iterator<Item> { boolean hasNext(); Item next(); optional; use void remove(); at your own risk } public boolean hasNext() { return current != null; } public void remove() { /* not supported */ } public Item next() { throw UnsupportedOperationException Item item = current.item; throw NoSuchElementException if no more items in iteration current = current.next; return item; } equivalent code (longhand) } Iterator<String> i = stack.iterator(); while (i.hasNext()) { String s = i.next(); StdOut.println(s); } } first times 43 current of best the was it null 44 Stack iterator: array implementation Iteration: concurrent modification Q. What if client modifies the data structure while iterating? import java.util.Iterator; A. A fail-fast iterator throws a java.util.ConcurrentModificationException. public class Stack<Item> implements Iterable<Item> { … concurrent modification for (String s : stack) stack.push(s); public Iterator<Item> iterator() { return new ReverseArrayIterator(); } private class ReverseArrayIterator implements Iterator<Item> { private int i = N; public boolean hasNext() { public void remove() { public Item next() { return i > 0; /* not supported */ return s[--i]; } } } To detect: ・Count total number of push() and pop() operations in Stack. ・Save counts in *Iterator subclass upon creation. ・If, when calling next() and hasNext(), the current counts do not equal } } i s[] the saved counts, throw exception. N it was the best of times null null null null 0 1 2 3 4 5 6 7 8 9 45 46 Java collections library List interface. java.util.List is API for an sequence of items. public interface List<Item> implements Iterable<Item> List() 1.3 B AGS, Q UEUES, AND S TACKS boolean isEmpty() int size() Algorithms R OBERT S EDGEWICK | K EVIN W AYNE http://algs4.cs.princeton.edu ‣ stacks void add(Item item) ‣ resizing arrays Item get(int index) ‣ queues Item remove(int index) ‣ generics ‣ iterators ‣ applications boolean contains(Item item) Iteartor<Item> iterator() create an empty list is the list empty? number of items append item to the end return item at given index return and delete item at given index does the list contain the given item? iterator over all items in the list ... Implementations. java.util.ArrayList uses resizing array; java.util.LinkedList uses linked list. caveat: only some operations are efficient 48 Java collections library Java collections library java.util.Stack. java.util.Stack. ・Supports push(), pop(), and and iteration. ・Extends java.util.Vector, which implements java.util.List ・Supports push(), pop(), and and iteration. ・Extends java.util.Vector, which implements java.util.List interface from previous slide, including get() and remove(). interface from previous slide, including get() and remove(). ・Bloated and poorly-designed API (why?) ・Bloated and poorly-designed API (why?) Java 1.3 bug report (June 27, 2001) The iterator method on java.util.Stack iterates through a Stack from the bottom up. One would think that it should iterate as if it were popping off the top of the Stack. status (closed, will not fix) java.util.Queue. An interface, not an implementation of a queue. It was an incorrect design decision to have Stack extend Vector ("is-a" rather than "has-a"). We sympathize with the submitter but cannot fix this because of compatibility. Best practices. Use our implementations of Stack, Queue, and Bag. 49 War story (from Assignment 1) Stack applications Generate random open sites in an N-by-N percolation system. ・Jenny: percolates blocked pick (i, j) at random; if already open, repeat. does not percolate site Takes ~ c1 N 2 seconds. ・Kenny: create a java.util.ArrayList of N 2 closed sites. Pick an index at random and delete. open Takes ~ c2 N 4 seconds. 50 site open site connected to top no open site connected to top ・Parsing in a compiler. ・Java virtual machine. ・Undo in a word processor. ・Back button in a Web browser. ・PostScript language for printers. ・Implementing function calls in a compiler. ・... Why is my program so slow? Kenny Lesson. Don't use a library until you understand its API! This course. Can't use a library until we've implemented it in class. 51 52 it is easy to convince yourself that it computes the proper value: any time the algorithm encounters a subexpression consisting of two operands separated by an op- Function calls Arithmetic expressionerator, evaluation all surrounded by parentheses, it leaves the result of performing that operation on those operands on the operand stack. The result is the same as if that value had appeared in the input instead of the subexpression, so we can think of replacing valuethe stack Goal. Evaluate infix expressions. (1+((2+3)*(4*5))) subexpression by the value to get an expression operator stack that would yield the same result. We can apply 1 +((2+3)*(4*5))) this argument again and again until we get a ( 1 + ( ( 2 + 3 ) * ( 4 * 5value. ) )For) example, the algorithm comsingle 1 ((2+3)*(4*5))) putes the same value of all of these expres+ sions: 1 2 How a compiler implements a function. ・Function call: push local environment and return address. ・Return: pop return address and local environment. operand Recursive function. Function that calls itself. Note. Can always use an explicit stack to remove recursion. operator ( 1 ( 1 ( 1 ( 1 101 + + + + ( ( ( 5 ( 5 100 2 + 3 ) * ( 4 * 5 ) ) ) * ( 4 * 5 ) ) ) * 20 ) ) ) Two-stack algorithm. [E. W. Dijkstra] static int gcd(int p, int q) { if (q == 0) return p; else return gcd(q,gcd p %(192, q); 24) } static int gcd(int p, int q) { p = 192, q = 24 if (q == 0) return p; gcd else return gcd(q, p % (24, q); 0) } static int gcd(int p, int q) { if (q == 0) return p; p = 24, q = 0 else return gcd(q, p % q); } p = 216, q = 192 53 Dijkstra's two-stack algorithm demo value stack 1 + ( ( 2 + operand 3 )*(4*5))) 54 Arithmetic expression evaluation public class Evaluate { public static void main(String[] args) { Stack<String> ops = new Stack<String>(); Stack<Double> vals = new Stack<Double>(); while (!StdIn.isEmpty()) { String s = StdIn.readString(); if (s.equals("(")) ; else if (s.equals("+")) ops.push(s); else if (s.equals("*")) ops.push(s); else if (s.equals(")")) { String op = ops.pop(); if (op.equals("+")) vals.push(vals.pop() + vals.pop()); else if (op.equals("*")) 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 operator stack (fully parenthesized) ( 3)*(4*5))) 1 2 3 + + (PROGRAM 4.3.5) is an implemen1 5 Value: push onto the stack.This code is a simple tationvalue of this method. *(4*5))) + example of an interpreter : a program that in1 5 Operator: push onto the operator stack. terprets the computation specified by a given (4*5))) + * string and performs the computation to ar1 5 4 Left parenthesis: ignore. rive at the result. A compiler is a program that *5))) + * the string into code on a lower-level Right parenthesis: converts pop operator and two values; 1 5 4 machine that can do the job. This conversion 5))) + * * is a more complicated process than the steppush the result of applying that operator 1 5 4 5 by-step conversion used by an interpreter, but ))) + * * it is based the same underlying to those values onto the on operand stack.mechanism. 1 5 20 Initially, Java was based on using an interpret)) + * er. Now, however, the Java system includes a 1 100 compiler that converts arithmetic expressions ) + (and, more generally, Java programs) into code 101 for the Java virtual machine, an imaginary maContext. An interpreter! chine that is easy to simulate on an actual computer. Trace of expression evaluation (Program 4.3.5) introJava.indb 573 infix expression +3)*(4*5))) Evaluate ・ ・ ・ ・ gcd (216, 192) + 1 2 + + ) * ( 4 * 5 ) ) ) 1/3/08 4:16:56 operator 55 56 Correctness Stack-based programming languages Q. Why correct? Observation 1. Dijkstra's two-stack algorithm computes the same value if A. When algorithm encounters an operator surrounded by two values the operator occurs after the two values. within parentheses, it leaves the result on the value stack. ( 1 + ( ( 2 + 3 ) * ( 4 * 5 ) ) ) ( 1 ( ( 2 3 + ) ( 4 5 * ) * ) + ) as if the original input were: Observation 2. All of the parentheses are redundant! ( 1 + ( 5 * ( 4 * 5 ) ) ) 1 2 3 + 4 5 * * + Jan Lukasiewicz Repeating the argument: ( 1 + ( 5 * 20 ) ) ( 1 + 100 ) 101 Bottom line. Postfix or "reverse Polish" notation. Extensions. More ops, precedence order, associativity. Applications. Postscript, Forth, calculators, Java virtual machine, … 57 58