Download Fundamentals of Python: From First Programs Through Data

Survey
yes no Was this document useful for you?
   Thank you for your participation!

* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project

Document related concepts
no text concepts found
Transcript
Fundamentals of Python:
From First Programs Through Data
Structures
Chapter 14
Linear Collections: Stacks
Objectives
After completing this chapter, you will be able to:
• Describe the behavior of a stack from a user’s
perspective
• Explain how a stack can be used to support a
backtracking algorithm
• Describe the use of a stack in evaluating postfix
expressions
Fundamentals of Python: From First Programs Through Data Structures
2
Objectives (continued)
• Explain how the Python virtual machine uses a
stack to support function and method calls
• Analyze the performance trade-offs between an
array-based implementation of a stack and a linked
implementation of a stack
Fundamentals of Python: From First Programs Through Data Structures
3
Overview of Stacks
• Stack: LIFO structure in which access is
completely restricted to just one end, called the top
– Basic operations: push and pop
Fundamentals of Python: From First Programs Through Data Structures
4
Using a Stack
• A stack type is not built into Python
• Can use a Python list to emulate a stack
– Use append to push and pop to pop
– Drawback: stack can be manipulated by all of the
other list operations as well
• Extra operations violate the spirit of a stack as an ADT
• We define a more restricted interface or set of
operations for any authentic stack implementation
and show how these operations are used in a brief
example
Fundamentals of Python: From First Programs Through Data Structures
5
The Stack Interface
Fundamentals of Python: From First Programs Through Data Structures
6
Instantiating a Stack
• We assume that any stack class that implements
this interface will also have a constructor that
allows its user to create a new stack instance
• Later, we’ll consider two different implementations:
– ArrayStack and LinkedStack
• With different performance trade-offs
• For now, assume that someone has coded these
so we can use them:
s1 = ArrayStack()
s2 = LinkedStack()
Fundamentals of Python: From First Programs Through Data Structures
7
Example Application: Matching
Parentheses
• Compilers need to determine if the bracketing
symbols in expressions are balanced correctly
Fundamentals of Python: From First Programs Through Data Structures
8
Example Application: Matching
Parentheses (continued)
• Approach 1: Count left and right parentheses
– Does not work
• Approach 2:
– Scan expression; push left brackets onto a stack
– On encountering a closing bracket, if stack is empty
or if item on top of stack is not an opening bracket of
the same type, we know the brackets do not balance
– Pop an item off the top of the stack and, if it is the
right type, continue scanning the expression
– When we reach the end of the expression, stack
should be empty; if not, brackets do not balance
Fundamentals of Python: From First Programs Through Data Structures
9
Three Applications of Stacks
• We now discuss three other applications of stacks:
– First, we present algorithms for evaluating arithmetic
expressions
– Second, we describe a general technique for using
stacks to solve backtracking problems
– Third, we examine the role of stacks in computer
memory management
Fundamentals of Python: From First Programs Through Data Structures
10
Evaluating Arithmetic Expressions
• In the infix form of an arithmetic expression, each
operator is located between its operands
• In the postfix form of an arithmetic expression, an
operator immediately follows its operands
Fundamentals of Python: From First Programs Through Data Structures
11
Evaluating Postfix Expressions
• Steps:
– Scan across the expression from left to right
– On encountering an operator, apply it to the two
preceding operands; replace all three by the result
– Continue scanning until you reach expression’s end,
at which point only the expression’s value remains
• To express this procedure as a computer
algorithm, you use a stack of operands
– The time complexity of the algorithm is O(n), where n
is the number of tokens in the expression
Fundamentals of Python: From First Programs Through Data Structures
12
Evaluating Postfix Expressions
(continued)
• In the algorithm, token refers to an operand or an
operator:
Create a new stack
While there are more tokens in the expression
Get the next token
If the token is an operand
Push the operand onto the stack
Else if the token is an operator
Pop the top-two operands from the stack
Apply the operator to the two operands just popped
Push the resulting value onto the stack
Return the value at the top of the stack
Fundamentals of Python: From First Programs Through Data Structures
13
Evaluating Postfix Expressions
(continued)
Fundamentals of Python: From First Programs Through Data Structures
14
Converting Infix to Postfix
• Start with an empty postfix expression and an
empty stack
– Stack will hold operators and left parentheses
• Scan across infix expression from left to right
• On encountering an operand, append it to postfix
expression
• On encountering a (, push it onto the stack
Fundamentals of Python: From First Programs Through Data Structures
15
Converting Infix to Postfix (continued)
• On encountering an operator
– Pop operators with equal or higher precedence
– Append them to postfix expression
– Push scanned operator onto stack
• On encountering a ), shift operators from stack to
postfix expression until meeting matching (, which
is discarded
• On encountering the end of the infix expression,
transfer remaining operators from the stack to the
postfix expression
Fundamentals of Python: From First Programs Through Data Structures
16
Backtracking
• A backtracking algorithm begins in a predefined
starting state and moves from state to state in
search of a desired ending state
– When there is a choice between alternative states,
picks one, possibly at random, and continues
– If it reaches a state that represents an undesirable
outcome, it backs up to last point at which there was
an unexplored alternative and tries it
– It searches all states or reaches desired ending state
• Two implementation techniques:
– Use stacks or use recursion
Fundamentals of Python: From First Programs Through Data Structures
17
Backtracking (continued)
• Stack approach:
Create an empty stack
Push the starting state onto the stack
While the stack is not empty
Pop the stack and examine the state
If the state represents an ending state
Return SUCCESSFUL CONCLUSION
Else if the state has not been visited previously
Mark the state as visited
Push onto the stack all unvisited adjacent states
Return UNSUCCESSFUL CONCLUSION
Fundamentals of Python: From First Programs Through Data Structures
18
Backtracking (continued)
• Backtracking algorithm to solve maze problem:
Instantiate a stack
Locate the character “P” in the grid
Push its location onto the stack
While the stack is not empty
Pop a location, (row, column), off the stack
If the grid contains “T” at this location, then
A path has been found
Return SUCCESS
Else if this location does not contain a dot
Place a dot in the grid at this location
Examine the adjacent cells to this one and
for each one that contains a space,
push its location onto the stack
Return FAILURE
Fundamentals of Python: From First Programs Through Data Structures
19
Memory Management
• The computer’s run-time system must keep track of
various details that are invisible to the programmer:
– Associating variables with data objects stored in
memory so they can be located when these
variables are referenced
– Remembering the address of the instruction in which
a method or function is called, so control can return
to the next instruction when that function or method
finishes execution
– Allocating memory for a function’s or a method’s
arguments and temporary variables, which exist only
during the execution of that function or method
Fundamentals of Python: From First Programs Through Data Structures
20
Memory Management (continued)
Fundamentals of Python: From First Programs Through Data Structures
21
Memory Management (continued)
• When a subroutine is called, the PVM:
– Creates the subroutine’s activation record and
pushes it onto the call stack
– Saves the basePtr’s current value in the region
labeled Prev basePtr and sets the basePtr to the
new activation record’s base
– Saves the locationCounter’s current value in region
labeled Return Address and sets locationCounter to
the first instruction of the called subroutine
– Copies calling parameters into Parameters region
– Starts executing the called subroutine at location
indicated by locationCounter
Fundamentals of Python: From First Programs Through Data Structures
22
Memory Management (continued)
• When a subroutine has finished executing, the
PVM does the following:
– Reestablishes the settings needed by the calling
subroutine by restoring the values of the
locationCounter and the basePtr from values stored
in the activation record
– Pops the activation record from the call stack
– Resumes execution of the calling subroutine at the
location indicated by the locationCounter
Fundamentals of Python: From First Programs Through Data Structures
23
Implementations of Stacks
• Because of their simple behavior and linear
structure, stacks are implemented easily using
arrays or linked structures
• Our two implementations of stacks illustrate the
typical trade-offs involved in using these two
recurring approaches
Fundamentals of Python: From First Programs Through Data Structures
24
Test Driver
Fundamentals of Python: From First Programs Through Data Structures
25
Test Driver (continued)
• Output:
– Note that the items in the stack print from bottom to
top in the stack’s string representation, whereas
when they are popped, they print from top to bottom
Fundamentals of Python: From First Programs Through Data Structures
26
Array Implementation
• Built around an array called items and two
integers called top and size
– Initially, the array has a default capacity of 10
positions, top equals -1, and size equals 0
Fundamentals of Python: From First Programs Through Data Structures
27
Linked Implementation
• Uses a singly linked sequence of nodes with a
variable top pointing at the list’s head, and a
variable size to track the items on the stack
Fundamentals of Python: From First Programs Through Data Structures
28
Linked Implementation (continued)
• The implementation of str is complicated by the
fact that the items must be visited from the end of
the linked structure to its beginning
– Solution: use recursion
Fundamentals of Python: From First Programs Through Data Structures
29
Linked Implementation (continued)
Fundamentals of Python: From First Programs Through Data Structures
30
Linked Implementation (continued)
Fundamentals of Python: From First Programs Through Data Structures
31
Time and Space Analysis of the Two
Implementations
• With the exception of __str__, all of the stack
methods have a maximum running time of O(1)
– __str__ runs in linear time; recursive function used
in linked stack causes a linear growth of memory
• In the array implementation, at the moment of
doubling, push’s running time jumps to O(n)
– The rest of the time it remains at O(1)
– Similar remarks can be made about pop
• Space requirement: 2n + 2 for linked stack and
capacity + 2 for array implementation
Fundamentals of Python: From First Programs Through Data Structures
32
Case Study: Evaluating Postfix
Expressions
• Request:
– Write an interactive program for evaluating postfix
expressions
• Analysis:
– Program should detect and report all input errors, be
they intentional or unintentional
– The view class is named PFView
– The model class is named PFEvaluatorModel
• Processes are worth encapsulating in separate
classes: Scanner and PFEvaluator
Fundamentals of Python: From First Programs Through Data Structures
33
Case Study: Evaluating Postfix
Expressions (continued)
Fundamentals of Python: From First Programs Through Data Structures
34
Case Study: Evaluating Postfix
Expressions (continued)
Fundamentals of Python: From First Programs Through Data Structures
35
Case Study: Evaluating Postfix
Expressions (continued)
Fundamentals of Python: From First Programs Through Data Structures
36
Case Study: Evaluating Postfix
Expressions (continued)
Fundamentals of Python: From First Programs Through Data Structures
37
Case Study: Evaluating Postfix
Expressions (continued)
• Implementation:
Fundamentals of Python: From First Programs Through Data Structures
38
Case Study: Evaluating Postfix
Expressions (continued)
Fundamentals of Python: From First Programs Through Data Structures
39
Summary
• A stack allows access to one end only, called the
top, where items are pushed onto or popped from
• Stacks are used in applications that manage data
items in LIFO manner, such as:
– Matching bracket symbols in expressions
– Evaluating postfix expressions
– Backtracking algorithms
– Managing memory for subroutine calls on a VM
• Arrays and singly linked structures support simple
implementations of stacks
Fundamentals of Python: From First Programs Through Data Structures
40