40
Fundamentals of Python: From First Programs Through Data Structures Chapter 14 Linear Collections: Stacks

Fundamentals of Python: From First Programs Through Data Structures

  • Upload
    avian

  • View
    32

  • Download
    1

Embed Size (px)

DESCRIPTION

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 - PowerPoint PPT Presentation

Citation preview

Page 1: Fundamentals of Python: From First Programs Through Data Structures

Fundamentals of Python:From First Programs Through Data

Structures

Chapter 14Linear Collections: Stacks

Page 2: Fundamentals of Python: From First Programs Through Data Structures

Fundamentals of Python: From First Programs Through Data Structures 2

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

Page 3: Fundamentals of Python: From First Programs Through Data Structures

Fundamentals of Python: From First Programs Through Data Structures 3

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

Page 4: Fundamentals of Python: From First Programs Through Data Structures

Fundamentals of Python: From First Programs Through Data Structures 4

Overview of Stacks

• Stack: LIFO structure in which access is completely restricted to just one end, called the top– Basic operations: push and pop

Page 5: Fundamentals of Python: From First Programs Through Data Structures

Fundamentals of Python: From First Programs Through Data Structures 5

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

Page 6: Fundamentals of Python: From First Programs Through Data Structures

Fundamentals of Python: From First Programs Through Data Structures 6

The Stack Interface

Page 7: Fundamentals of Python: From First Programs Through Data Structures

Fundamentals of Python: From First Programs Through Data Structures 7

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()

Page 8: Fundamentals of Python: From First Programs Through Data Structures

Fundamentals of Python: From First Programs Through Data Structures 8

Example Application: Matching Parentheses

• Compilers need to determine if the bracketing symbols in expressions are balanced correctly

Page 9: Fundamentals of Python: From First Programs Through Data Structures

Fundamentals of Python: From First Programs Through Data Structures 9

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

Page 10: Fundamentals of Python: From First Programs Through Data Structures

Fundamentals of Python: From First Programs Through Data Structures 10

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

Page 11: Fundamentals of Python: From First Programs Through Data Structures

Fundamentals of Python: From First Programs Through Data Structures 11

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

Page 12: Fundamentals of Python: From First Programs Through Data Structures

Fundamentals of Python: From First Programs Through Data Structures 12

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

Page 13: Fundamentals of Python: From First Programs Through Data Structures

Fundamentals of Python: From First Programs Through Data Structures 13

Evaluating Postfix Expressions (continued)

• In the algorithm, token refers to an operand or an operator:Create a new stackWhile there are more tokens in the expression

Get the next tokenIf the token is an operand

Push the operand onto the stackElse if the token is an operator

Pop the top-two operands from the stackApply the operator to the two operands just poppedPush the resulting value onto the stack

Return the value at the top of the stack

Page 14: Fundamentals of Python: From First Programs Through Data Structures

Fundamentals of Python: From First Programs Through Data Structures 14

Evaluating Postfix Expressions (continued)

Page 15: Fundamentals of Python: From First Programs Through Data Structures

Fundamentals of Python: From First Programs Through Data Structures 15

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

Page 16: Fundamentals of Python: From First Programs Through Data Structures

Fundamentals of Python: From First Programs Through Data Structures 16

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

Page 17: Fundamentals of Python: From First Programs Through Data Structures

Fundamentals of Python: From First Programs Through Data Structures 17

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

Page 18: Fundamentals of Python: From First Programs Through Data Structures

Fundamentals of Python: From First Programs Through Data Structures 18

Backtracking (continued)

• Stack approach:Create an empty stackPush the starting state onto the stackWhile the stack is not empty

Pop the stack and examine the stateIf the state represents an ending state

Return SUCCESSFUL CONCLUSIONElse if the state has not been visited previously

Mark the state as visitedPush onto the stack all unvisited adjacent states

Return UNSUCCESSFUL CONCLUSION

Page 19: Fundamentals of Python: From First Programs Through Data Structures

Fundamentals of Python: From First Programs Through Data Structures 19

Backtracking (continued)

• Backtracking algorithm to solve maze problem:Instantiate a stackLocate the character “P” in the gridPush its location onto the stackWhile the stack is not empty

Pop a location, (row, column), off the stackIf the grid contains “T” at this location, then

A path has been foundReturn SUCCESS

Else if this location does not contain a dotPlace a dot in the grid at this locationExamine the adjacent cells to this one andfor each one that contains a space,

push its location onto the stackReturn FAILURE

Page 20: Fundamentals of Python: From First Programs Through Data Structures

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

Page 21: Fundamentals of Python: From First Programs Through Data Structures

Fundamentals of Python: From First Programs Through Data Structures 21

Memory Management (continued)

Page 22: Fundamentals of Python: From First Programs Through Data Structures

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

Page 23: Fundamentals of Python: From First Programs Through Data Structures

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

Page 24: Fundamentals of Python: From First Programs Through Data Structures

Fundamentals of Python: From First Programs Through Data Structures 24

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

Page 25: Fundamentals of Python: From First Programs Through Data Structures

Fundamentals of Python: From First Programs Through Data Structures 25

Test Driver

Page 26: Fundamentals of Python: From First Programs Through Data Structures

Fundamentals of Python: From First Programs Through Data Structures 26

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

Page 27: Fundamentals of Python: From First Programs Through Data Structures

Fundamentals of Python: From First Programs Through Data Structures 27

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

Page 28: Fundamentals of Python: From First Programs Through Data Structures

Fundamentals of Python: From First Programs Through Data Structures 28

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

Page 29: Fundamentals of Python: From First Programs Through Data Structures

Fundamentals of Python: From First Programs Through Data Structures 29

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

Page 30: Fundamentals of Python: From First Programs Through Data Structures

Fundamentals of Python: From First Programs Through Data Structures 30

Linked Implementation (continued)

Page 31: Fundamentals of Python: From First Programs Through Data Structures

Fundamentals of Python: From First Programs Through Data Structures 31

Linked Implementation (continued)

Page 32: Fundamentals of Python: From First Programs Through Data Structures

Fundamentals of Python: From First Programs Through Data Structures 32

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

Page 33: Fundamentals of Python: From First Programs Through Data Structures

Fundamentals of Python: From First Programs Through Data Structures 33

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

Page 34: Fundamentals of Python: From First Programs Through Data Structures

Fundamentals of Python: From First Programs Through Data Structures 34

Case Study: Evaluating Postfix Expressions (continued)

Page 35: Fundamentals of Python: From First Programs Through Data Structures

Fundamentals of Python: From First Programs Through Data Structures 35

Case Study: Evaluating Postfix Expressions (continued)

Page 36: Fundamentals of Python: From First Programs Through Data Structures

Fundamentals of Python: From First Programs Through Data Structures 36

Case Study: Evaluating Postfix Expressions (continued)

Page 37: Fundamentals of Python: From First Programs Through Data Structures

Fundamentals of Python: From First Programs Through Data Structures 37

Case Study: Evaluating Postfix Expressions (continued)

Page 38: Fundamentals of Python: From First Programs Through Data Structures

Fundamentals of Python: From First Programs Through Data Structures 38

Case Study: Evaluating Postfix Expressions (continued)

• Implementation:

Page 39: Fundamentals of Python: From First Programs Through Data Structures

Fundamentals of Python: From First Programs Through Data Structures 39

Case Study: Evaluating Postfix Expressions (continued)

Page 40: Fundamentals of Python: From First Programs Through Data Structures

Fundamentals of Python: From First Programs Through Data Structures 40

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