Transcript Stacks
Stacks
Chapter 5
Chapter Objectives
• To learn about the stack data type and how to use its
four methods: push, pop, peek, and empty
• To understand how Java implements a stack
• To learn how to implement a stack using an underlying
array or a linked list
• To see how to use a stack to perform various
applications, including finding palindromes, testing for
balanced (properly nested) parentheses, and evaluating
arithmetic expressions
Chapter 5: Stacks
2
Stack
• Dinner plates at a cafeteria
• Spring-loaded “stack” of plates
• “Push” a new plate onto the stack
• “Pop” an existing plate off of the stack
• Only the top plate is accessible
• “Last-In, First-Out”, or LIFO
Chapter 5: Stacks
3
Stack
• Pez dispenser also uses a stack
• Only the top Pez candy can be accessed
• Can only extract one item at a time
• “Push” candy onto stack
• “Pop” candy off of stack
• Only the top candy is accessible, LIFO, etc.
Chapter 5: Stacks
4
Stack
• Stack might seem to be too restrictive
• LIFO
• Only one element accessible
• Only operations are push, pop, peek, empty
• However, stacks are extremely useful in CS
• Simple and useful
• For example, stacks used when executing programs
• Used like “scratch paper” to keep track of info
Chapter 5: Stacks
5
Specification of the Stack Abstract Data
Type
• Only the top element of a stack is visible, therefore the
number of operations performed by a stack are few
• The only operations available are
• Inspect the top element (peek)
• Retrieve (and remove) the top element (pop)
• Put a new element on the stack (push)
• Test for an empty stack (empty)
Chapter 5: Stacks
6
Specification of the Stack Abstract Data
Type (continued)
Chapter 5: Stacks
7
StackInt<E> Interface
/** Stack is a LIFO data structure */
public interface StackInt < E > {
/** Pushes an item onto the top of the stack and
returns the item pushed. */
E push(E obj);
/** Returns the object at the top of
the stack without removing it. */
E peek();
/** Returns the object at the top of the stack
and removes it. */
E pop();
/** Returns true if the stack is empty;
otherwise, returns false.*/
boolean empty();}
Chapter 5: Stacks
8
Stack Example
• Suppose we have a stack called names
Trudy
Bob
Alice
• And we execute names.pop();
• What is the return value?
• “Trudy” and the stack is
Bob
Alice
Chapter 5: Stacks
9
Stack Example
• We now have the stack
Bob
Alice
• And we execute names.push(“Charlie”);
• What is the return value?
• “Charlie” and stack is
Charlie
Bob
Alice
Chapter 5: Stacks
10
Stack Example
• We now have the stack
Charlie
Bob
Alice
• And we execute names.peek();
• What is the return value?
• “Charlie” and stack is
Charlie
Bob
Alice
Chapter 5: Stacks
11
Stack Example
• We now have the stack
Charlie
Bob
Alice
• And we execute names.empty();
• What is return value?
• Returns false and stack is
Charlie
Bob
Alice
Chapter 5: Stacks
12
Stack Applications
• We consider two programs that use stacks
• Palindrome finder
• Parentheses matcher
• First we consider palindrome finder
• Palindrome: reads the same in either direction
• For example: “level” and “Able was I ere I saw Elba”
• Note that we do not ignore spaces and punctuation
• So, for example, “never odd or even” not considered
a palindrome for this exercise (but often it is)
Chapter 5: Stacks
13
Palindrome Finder
• Input: string to be tested
• Output: message indicating whether string is a
palindrome or not
• How to slove this problem?
• Many different ways to solve this…
• For example, could create a new string by going from
end to beginning of original string
• Then compare new and original strings
• If equal, string is a palindrome
• But we want to use a stack!
Chapter 5: Stacks
14
Palindrome Finder
• Using a stack…
• Push characters of original string onto stack
• Then pop characters off and append to new string
• Compare new string and original string
• If same, then it is a palindrome
• Why does this work?
• If we push, then pop, it will reverse string
Chapter 5: Stacks
15
Palindrome Finder
• Suppose string is “frank”
• First, push letters onto stack…
frank
f
frank
r
f
frank
a
r
f
frank
n
a
r
f
Chapter 5: Stacks
frank
k
n
a
r
f
16
Palindrome Finder
• Then pop letters off of stack and append to new string…
k
kn
kna
knar
k
n
a
r
f
n
a
r
f
a
r
f
r
f
knarf
f
• Finally, compare original and new string:
• We have frank != knarf, so not a palindrome
Chapter 5: Stacks
17
Class PalindromeFinder
Chapter 5: Stacks
18
Testing PalindromeFinder
• What types of strings should be test???
• Single character (which is always a palindrome)
• Single words
• Both palindromes and non-palindromes
• Multiple words
• Both palindromes and non-palindromes
• Different cases (upper/lower)
• Even-length strings
• Odd-length strings
• Empty string (considered palindrome by default)
Chapter 5: Stacks
19
Balanced Parenthesis
• It is important to determine whether an expression is
“balanced” with respect to parentheses
• For example
• (a+b*(c/(d-e)))+(d/e) is balanced
• But
• (a+b*(c/d-e)))+(d/e) is not balanced
• Problem is more complicated if braces or brackets
(square and/or curly) are also used
• Good solution is to use stacks!
• Here, we only consider parenthesis
Chapter 5: Stacks
20
ParenChecker Class
• Input: String (representing an expression)
• Output: A message indicating whether expression is
balanced with respect to parenthesis or not
• Of course, we want to use a stack…
• What is the idea behind the algorithm?
• Push open parenthesis onto stack
• When closed parenthesis is encountered
• Try to pop top element off of stack
• If no top element (stack is empty), not balanced
• When done, if stack is not empty, then not balanced
Chapter 5: Stacks
21
ParenChecker Algorithm
•
•
•
•
•
Given expression to test…
Create an empty stack of characters
Set balanced = true (i.e., assume it is balanced)
Set index = 0
While balanced is true and index < expression length
• Get the next character in expression
• If character in open parenthesis
• Push open parenthesis onto stack
• Else if character is closing parenthesis
• If stack is empty, set balanced to false
• Else pop element from stack
• Increment index
• Return true if balanced is true and stack is empty
Chapter 5: Stacks
22
ParenChecker Class
Chapter 5: Stacks
23
ParenChecker Testing
•
•
•
•
What data to test on?
Simple valid expressions (one level of matched parens)
Simple invalid expressions
More complex expressions (valid and invalid)
• Test too many open parens and too many closed
parens
• Know the correct answer before testing an expression
Chapter 5: Stacks
24
Implementing a Stack
• In Java, Stack class extends Vector
• Could also have been implemented using other Lists
• Such as ArrayList or LinkedList
• Could also be implemented using Array
• We’ll look (briefly) at each of these
Chapter 5: Stacks
25
Stack as a Vector
• The Java API includes a Stack class as part of the
package java.util
• The Vector class implements a growable array
• Elements of a vector accessed using an integer index
• Size can grow or shrink as needed to accommodate
the adding and removing of elements
• In following examples, push letters of “Java” onto stack:
a
v
a
J
Chapter 5: Stacks
26
Stack as a Vector
Chapter 5: Stacks
27
Stack as a Vector
•
•
•
•
Java Stack is an extension of Vector
Therefore, can use all Vector methods on a Stack
Is this a good thing?
You can access any element of a Vector
• So, you can access any element of a Stack
• If you try to access elements of a Stack, you might get
ArrayIndexOutOfBoundsException
• Best to restrict yourself to stack-specific methods
Chapter 5: Stacks
28
Stack as a List
• Can use ArrayList, Vector, LinkedList classes
• Since all implement the List interface
• Name of class illustrated in text is ListStack<E>
• Note that ListStack is an adapter class
• Gives different names to essentially same operations
• Also true of Java’s Vector-based implementation
• For example, java.util.Stack<E> push is code is
public E push(E obj) {
add(obj);
return obj;
}
Chapter 5: Stacks
29
ListStack.java
public class ListStack < E > implements StackInt < E > {
private List < E > theData;
public ListStack() {
theData = new ArrayList < E > ();
}
public E push(E obj) {
theData.add(obj);
return obj;
}
...
Chapter 5: Stacks
30
Stack as an Array
• Allocate storage for an array with an initial default
capacity when creating a new stack object
• Keep track of the top of the stack, topOfStack
• For empty stack, topOfStack is set to -1
• No size method
• Array size does not grow/shrink after each push/pop
• However, must reallocate if more space needed
• This is very primitive
• And that’s why I like it best…
Chapter 5: Stacks
31
Stack as an Array
Chapter 5: Stacks
32
Stack as an Array
public class ArrayStack < E > implements StackInt < E > {
E[] theData;
int topOfStack = -1;
private static final int INITIAL_CAPACITY = 10;
public ArrayStack() {
theData = (E[])new Object[INITIAL_CAPACITY];
}
public E push(E obj) {
if (topOfStack == theData.length - 1) {
reallocate();
}
topOfStack++;
theData[topOfStack] = obj;
return obj;
}
...
Chapter 5: Stacks
33
Stack as a Linked List
• Can implement a stack using a linked list of nodes
• See code and details in text
Chapter 5: Stacks
34
Comparison of Stack Implementations
• Extending a Vector (as is done by Java) is a poor choice
• All Vector methods are accessible
• Then why does Java do it this way?
• What about ArrayList implementation?
• Easiest to implement, ArrayList does all of the work…
• What about Array implementation?
• Slightly more difficult for programmer
• What about Linked List implementation?
• Uses only as much storage as needed
• However, links are essentially wasted
• Regardless of method used, push/pop is O(1)
Chapter 5: Stacks
35
Stack Application
• We consider problem of evaluating math expressions
• Postfix and infix notation
• Expressions normally written in infix form
• Operators (+,-,*,/, etc.) between the operands
• Good for humans, not so good for computers
• Computers prefer postfix notation
• Operands come first, then operators
Chapter 5: Stacks
36
Postfix vs Infix
Chapter 5: Stacks
37
Postfix Advantages
• Advantage of postfix form include
• No need for parentheses
• No need to consider operator precedence
Chapter 5: Stacks
38
Evaluating Postfix Expressions
• Problem: Write a class to evaluate postfix expressions.
• Analysis: Stack is good data structure to store operands
until needed
• Design: Class PostfixEvaluator with methods
• Method eval: scans postfix expression and processes
its tokens
• Method evalOp: evaluates each operator
• Method isOperator: determine whether a character is
an operator
Chapter 5: Stacks
39
Evaluating Postfix Expressions
Chapter 5: Stacks
40
Evaluating Postfix Expressions
Chapter 5: Stacks
41
Evaluating Postfix Expressions
Chapter 5: Stacks
42
Converting Infix to Postfix
Chapter 5: Stacks
43
Converting Infix to Postfix
Chapter 5: Stacks
44
Converting Infix to Postfix
Chapter 5: Stacks
45
Converting Infix to Postfix
Chapter 5: Stacks
46
Converting Infix to Postfix
Chapter 5: Stacks
47
Chapter Review
• A stack is a last-in, first-out (LIFO) data structure
• A stack is a simple but powerful data structure
• Four operations are empty, peek, pop, and push
• Stacks are useful to process information in the reverse of
the order that it is encountered
• In Java, Stack is implemented as an extension of the
Vector class
Chapter 5: Stacks
48
Chapter Review
• We considered 3 different ways to implement a stack:
• Using the List interface as a container
• Using an array as a container
• Using a linked list as a container
• We applied stacks to evaluate arithmetic expressions
Chapter 5: Stacks
49