0% found this document useful (0 votes)
29 views36 pages

4 Stacks and Queues

Uploaded by

Maxi Brad
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
29 views36 pages

4 Stacks and Queues

Uploaded by

Maxi Brad
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 36

COMPUTER SCIENCE

S E D G E W I C K / W A Y N E

SEDGEWICK

ntist WAYNE
Computer Science

ary
A N I N T E R D I S C I P L I N A RY A P P R O A C H

or

d
gs,
of

omputer
C cience Stacks and Queues
hem

h.

S
nce
d
wick

ysis
orics;
ver

An Interdisciplinary Approach

ROBERT SEDGEWICK
ANADA
K E V I N WAY N E
Section 4.3
COMPUTER SCIENCE
S E D G E W I C K / W A Y N E

Stacks and Queues


• Linked Lists
• Stacks and Queues
• Client Applications
• Implementations
Data types and data structures

Data types
• Set of values.
• Set of operations on those values.
• Some are built into Python int: int, float, str, . . .
• Most are not: complex, graphics, random, . . .

Data structures
• Represent data.
• Represent relationships among data.
• Some are built in to Python: lists, dictionaries, . . .
• Most are not: linked list, circular list, tree, . . .

Design challenge for every data type: Which data structure to use?
• Resource 1: How much memory is needed?
• Resource 2: How much time do data-type methods use?
3
Data structures: sequential versus linked

Array at C0 Linked list at C4


Sequential data structure
addr value addr value
• Put objects next to one another.
C0 "Alice" C0 "Carol"
• Machine: consecutive memory cells.
C1 "Bob" C1 null
• Python: array of objects - list.
C2 "Carol" C2
• Fixed size (we don’t realize), arbitrary access. i th element
C3 C3

C4 C4 "Alice"
Linked data structure C5 C5 CA
• Associate with each object a link to another one. C6 C6
• Machine: link is memory address of next object. C7 C7
• Python: link is reference to next object. C8 C8
• Variable size, sequential access. next element C9 C9
• Overlooked by novice programmers. CA CA "Bob"
• Flexible, widely used method for organizing data. CB CB C0
4
Simplest singly-linked data structure: linked list

Linked list
• A recursive data structure.
class _Node:
• A linked list is null or a reference to a node. def __init__(self, item =
• A node holds an item and a pointer to the next node in the list. None, next = None):
self._nextNode = next
self._item = item
Representation
• Use a private nested class _Node to implement the node abstraction.
• For simplicity, start with nodes having two attributes:
• an item
• a reference to a _Node object.

A linked list

first "Alice" "Bob" "Carol"


None
item next
5
Singly-linked data structures

Even with just one link ( ) a wide variety of data structures are possible.

Tree
Linked list (this lecture)
Rho

Circular list (TSP) General case

From the point of view of a particular object, all of


these structures look the same.

6
Building a linked list

third = _Node(“Carol”); addr value

C0 "Carol"
second = _Node(“Bob”, third)
C1 None
first = _Node(“Alice”, second) C2

C3
third C0
C4 "Alice"
second CA
C5 CA
first C4
C6

C7

C8

C9
first second third
CA "Bob"

"Alice" "Bob" "Carol" CB C0

None
7
List processing algorithms

Standard operations for processing data structured as a singly-linked list: addr value

• Add a node to the beginning of the list. C0 "Carol"

• Remove and return the node at the beginning. C1 null

• Add a node at the end of the list C2

• Requires a reference to the last node. C3

• Traverse the list, visiting every node, in sequence. C4 "Alice"

• Usually: Traverse list from first to last. C5 CA

• How to traverse in reverse order? Use unwind recursion! C6

C7

C8
…and an operation that, for efficiency, calls for a doubly-linked list
C9
• Remove and return the node at the end.
CA "Bob"
CB C0

8
List processing algorithms: Remove and return the first item

Goal. Remove and return the first


item in a linked list first.
first "Alice" "Bob" "Carol"

item
item = first._someItem "Alice" first "Alice" "Bob" "Carol"

item
first = first._nextNode "Alice" first "Alice" "Bob" "Carol"

available for garbage collection


item
return item "Alice" first "Bob" "Carol"

9
List processing algorithms: Add a new node at the beginning

item
Goal. Add item to a linked list first.
"Dave"

first "Alice" "Bob" "Carol"

second

second = first first "Alice" "Bob" "Carol"

second

first = _Node() first "Alice" "Bob" "Carol"

second

first._item = item
first "Dave" "Alice" "Bob" "Carol"
first._nextNode = second

10
List processing code: Add a new node at the end

item
Goal. Add item to the end of a linked list.
"Dave" last
Use and maintain a reference last
first "Alice" "Bob" "Carol"

item
"Dave" last

last.next = _Node()
first "Alice" "Bob" "Carol"

item
"Dave" last

last = last.next
first "Alice" "Bob" "Carol"

last

last.item = item first "Alice" "Bob" "Carol" "Dave"

11
List processing algorithms: Traverse a list

Goal. Visit every node on a linked list first.

x = first; x

while (x != None):
first "Alice" "Bob" "Carol"
print(x._someValue)
x = x._nextNode

List:
Alice
Output
Bob
Carol

To traverse in reverse order, see unwind.py

12
Implementation of a linked list
class LinkedList: def __iter__(self):
class _Node: # private nested class pointer = self._head
def __init__(self, item = None, nextNode = None): while pointer is not None:
self._nextNode = nextNode yield pointer._item
self._item = item pointer = pointer._nextNode

def __init__(self): def main():


self._head = None l = LinkedList()
for i in range(13): l.insert(i)
def insert(self, something):
self._head = self._Node(something, self._head) print("List in order of first to last:")
for i in l: print(i)
def isEmpty(self): List in order of first to last:
return self._head is None if __name__ == '__main__': 12
11
main() 10
# return item in the head and delete the first node 9
8
def delete(self):
7
t = None # in case there's nothing to delete 6
if self._head != None: 5
4
t = self._head._item 3
self._head = self._head._nextNode 2
1
return t
0 13
COMPUTER SCIENCE
S E D G E W I C K / W A Y N E

Stacks and Queues


• Linked Lists
• Stacks and Queues
• Client Applications
• Implementations
Recap: a linked list

first "Alice" "Bob" "Carol"

None
item next

15
Stack and Queue APIs

A collection is an ADT whose values are a multiset of items, usually, all of the same type.

Two fundamental collection ADTs differ in just a detail of the specification of their operations.

Add to the Take from the Take from the


beginning beginning beginning
Stack operations Queue operations
• Add an item to the collection. • Add an item to the collection.
• Remove and return the item most Last • Remove and return the item least First
In In
recently added (LIFO). recently added (FIFO). First
First
• Test if the collection is empty. Out • Test if the collection is empty. Out

• Return the size of the collection. • Return the size of the collection.

Add to the
Stacks and queues both arise naturally in countless applications. end

A key characteristic. No limit on the size of the collection.

16
Example of stack operations
push to the pop from the
top top

Push. Add an item to the collection.


Pop. Remove and return the item most recently added. Last
In
First
push to the Out
top pop from
the top

push to be or not to - be - - that - - - is


pop to be not that or be

to be
not not not not not that
stack contents
or or or or or or or or or
after
operation be be be be be be be be be be be is
to to to to to to to to to to to to to to

17
Example of queue operations
dequeue from the
beginning

Enqueue. Add an item to the collection.


First
Dequeue. Remove and return the item least recently added. In
First
Out

enqueue at
the end

enqueue to be or not to - be - - that - - - is


dequeue to be or not to be
dequeue from the beginning

to to to to to be be or not not to be that that

queue be be be be or or not to to be that is


contents after or or or not not to be be that
operation
not not to to be that
enqueue at
the end to be
18
APIs

Goal. Simple, safe, and clear client code for collections of any type of data.

class Stack
Stack() create a stack of items
push(item) add item to stack
Stack API
pop() remove and return the item most recently pushed
isEmpty() is the stack empty ?
size() # of objects on the stack

class Queue
Queue() create a queue of items
enqueue(item) add item to queue
Queue API
dequeue() remove and return the item least recently enqueued
isEmpty() is the queue empty ?
size() # of objects in the queue

19
Performance specifications

Challenge. Provide guarantees on performance.

Goal. Simple, safe, clear, and efficient client code.


Typically required for client
code to be scalable

• All operations are constant-time.

Performance
• Memory use is linear in the size of the collection,
specifications when it is nonempty.
• No limits within the code on the collection size.

Python. Any implementation of the API implements the stack/queue abstractions.

RS+KW. Implementations that do not meet performance specs do not implement the abstractions.

20
linkedstack.py
# Implemented as a linked-list of Node objects # Pop the top item from the stack and return it.
class Stack: def pop(self):
class _Node: # private nested class if self._first is None:
def __init__(self, item = None, nextNode = None): return None
self._nextNode = nextNode else:
self._item = item item = self._first._item
self._first = self._first._nextNode
# Construct an empty Stack object. return item
def __init__(self):
self._first = None # Reference to first _Node # Return string representation of stack. (Not in the
API.)
# Return True if stack is empty, False otherwise. def __str__(self):
def isEmpty(self): s = ""
return self._first is None cur = self._first
while cur is not None:
# Push item onto the top of stack. s += str(cur._item) + ", "
def push(self, item): cur = cur._nextNode
self._first = self._Node(item, self._first) return s[0:-2]

Note: This class does not fully implement the API shown before.
As a lab exercise you will add the code for size().
21
linkedstack.py
def main(): $: python3 linkedstack.py
s = Stack() Stack contents:
for i in range(13): s.push(i) 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0
Stack contents:
print("Stack contents:")
20, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0
print(str(s))
Removed: 20
Removed: 12
Stack contents:
s.push(20)
11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0
print("Stack contents:")
print(str(s))
There is an alternative implementation in the course
print("Removed:",str(s.pop())) shell, stack.py, implemented using the
print("Removed:",str(s.pop())) built in list type.
print("Stack contents:")
print(str(s)) Exercise: compare the implementations in two ways:
• visually
if __name__ == '__main__':
main()
• performance (use stopwatch.py)

22
linkedqueue.py

Test Client
• reads a text file, one line at a time
• parses each space-separated string, and adds it to the queue, using enqueue()
• ‘-’ is interpreted as a call to dequeue()

def main():
queue = Queue()
tobe.txt
output = "" # to record items removed from the queue
for line in fileinput.input(sys.argv[1:]): #read each to be or not to - be - - that - - - is
line in file
items = line.split(' ') # read each (space-
separated) item in line
for item in items:
$: python3 linkedqueue.py < tobe.txt
item = item.strip() # removes any leading and
to be or not to be
trailing spaces
if item != '-':
queue.enqueue(item)
else:
output += queue.dequeue() + " "
print(output)
23
COMPUTER SCIENCE
S E D G E W I C K / W A Y N E

Stacks and Queues

• Linked lists
• Stacks and Queues
• Client Applications
• Implementations
Stack and queue applications

Queues
• First-come-first-served resource allocation.
• Asynchronous data transfer (standard input,
standard output).
• Dispensing requests on a shared resource.
• Simulations of the real world.

Stacks
• Last-come-first-served resource allocation.
• Function calls in programming languages.
• Basic mechanism in interpreters, compilers.
• Fundamental abstraction in computing.

25
Stack example: "Back" button in a browser

Typical scenario
• Visit a page.
• Click a link to another page.
• Click a link to another page.
• Click a link to another page.
• Click "back" button.
• Click "back" button.
• Click "back" button.

https://introcs.cs.princeton.edu/python/43stack/

https://introcs.cs.princeton.edu/python/40algorithms/

https://introcs.cs.princeton.edu/python/home/
26
Stack client example: Postfix expression evaluation

Infix. Standard way of writing arithmetic expressions, using parentheses for precedence.

Example. ( 1 + ( ( 2 + 3 ) * ( 4 * 5 ) ) ) = ( 1 + ( 5 * 20) ) = 101

Postfix. Write operator after operands (instead of in between them).

Example. 1 2 3 + 4 5 * * + also called "reverse Polish" notation (RPN) Jan Łukasiewicz


1878−1956

Remarkable fact. No parentheses are needed!

1 2 3 + 4 5 * * +
There is only one way find first operator, convert to HP-35 (1972)
1 (2+3)4 5 * * + infix, enclose in ()
to parenthesize a First handheld calculator.
postfix expression. 1 ((2+3)*(4*5))+ "Enter" means "push".
iterate, treating subexpressions in
No parentheses.
parentheses as atomic
(1+((2+3)*(4*5)))

Next. With a stack, postfix expressions are easy to evaluate.


Made slide rules obsolete (!)
27
Postfix arithmetic expression evaluation

Algorithm
• While input stream is nonempty, read a token.
• Value: Push onto the stack.
• Operator: Pop operand(s), apply operator, push the result.

1 2 3 + 4 5 * * +
1 2 3 + 4 5 * * +

= 5 = 20= 100
= 101 5
3 4 4 20
2 2 5 5 5 5 100
1 1 1 1 1 1 1 1 101

28
Stack client example: postfix expression evaluation
from linkedstack import *
Input expression:

# compute value of postfix expression using a stack • must be in postfix form and contain:
def postfix(expr): • numbers (real or integer, ≥ 0)
s = Stack()
• operators from { +, -, *, / }
for term in expr:
if isinstance(term, int or float): s.push(term)
else: s.push(calc(s.pop(), s.pop(), term)) Output
return s.pop()
$: python3 postfix.py
21
# helper method performs an arithmetic operation
def calc(a, b, op):
if op == '+': return a + b Perspective:
elif op == '-': return a - b
elif op == '*': return a * b
• Easy to add operators of all sorts.
elif op == '/': return a / b • Can do infix with two stacks (see text).
• Could output machine language code.
def main():
print(postfix([6, 9, '-', 5, 2, '+', '*']))
• Indicative of how Python compiler works.

if __name__ == '__main__':
main()
29
COMPUTER SCIENCE
S E D G E W I C K / W A Y N E
PA R T I : P R O G R A M M I N G I N J AVA

Image sources

http://pixabay.com/en/book-stack-learn-knowledge-library-168824/
http://upload.wikimedia.org/wikipedia/commons/2/20/Cars_in_queue_to_enter_Gibraltar_from_Spain.jpg
COMPUTER SCIENCE
S E D G E W I C K / W A Y N E

Stacks and Queues

• Linked lists
• APIs
• Client Applications
• Implementations
Benchmarking the stack implementation

Stack implements the stack abstraction.

It does implement the API and meet the performance specifications.

class Stack
Stack() create a stack of items
push(item) add item to stack
Stack API
pop() remove and return the item most recently pushed
isEmpty() is the stack empty ?
size() # of objects on the stack

• All operations are constant-time. ✓


Performance
specifications • Memory use is linear in the size of the collection, when it is nonempty. ✓
• No limits within the code on the collection size. ✓
dequeue(): same code as pop()
enqueue(): slightly more complicated
Made possible by linked data structure.

Also possible to implement the queue abstraction with a singly-linked list (see text).
32
Performance can vary

Choose your data structure wisely! a = []


for i in range(n): quadratic time
• It can affect the performance of your code.
a.insert(0, 'slow')
• But also be careful how you use it.
• In particular, there is a hidden cost to arrays and lists. a = []
for i in range(n): linear time
a.insert(i, 'fast')
Why the difference?
• Because Python’s built in list type is implemented using an array.
• The array has a fixed size, which is doubled if filled.
• So usually there is space already available to add a new item to the end.
• So adding an extra item to the list takes approximately O(1) (constant) time.
• Hence adding n items to the end takes O(n) (linear) time.
• However, adding an item to the start of an array causes all previous items to be re-added.
• Which takes O(n) time.
• Hence adding n items to the start takes approximately O(n×n) = O(n2) (quadratic) time.

33
Performance can vary

# measure performance of insert() at start or print("insert at start:", time1, "seconds")


end of a list print("insert at end: ", time2, "seconds")
from stopwatch import *
def main(): if __name__ == '__main__':
n = int(sys.argv[1]) main()

total1 = 0.0 $: python3 inserttest.py 10000


insert at start: 0.019546985626220703 seconds
watch1 = Stopwatch()
insert at end: 0.0007841587066650391 seconds
a = []
for i in range(n):
a.insert(0, 'slow')
remember to ensure that stopwatch.py is in the same folder
time1 = watch1.elapsedTime()

total2 = 0.0
watch2 = Stopwatch()
a = []
for i in range(n):
a.insert(i, 'fast')
time2 = watch2.elapsedTime()
34
Summary
push to the pop from the dequeue from the
Stacks and queues beginning beginning beginning

• Fundamental collection abstractions.


First
• Differ only in order in which items are removed. Last
In
stack In queue
• Performance specifications: Constant-time for all operations First First
Out
and space linear in the number of objects. Out

enqueue at
the end
Linked structures
• Fundamental alternative to arrays.
• Enable implementations of the stack/queue abstractions that
meet performance specifications.

35
Reading and References

These Slides
• principally based on slides by Robert Sedgewick and Kevin Wayne, and Manrique Mata-Montero
Recommended Reading
• online booksite (Python version) chapter 4
focus on section 4.3
Suggested Wider Reading / Watch & Learn
• section 4.1 from the online booksite on analysis of algorithms
• this might provide some insight into the importance of choosing a data structure wisely!
• A video by Lucid Computing that explains the stack as its coded (one of a series)
Activity:
• complete Lab 2 when available
• download and play with the implementations of linked lists, stacks and queues found in the
course shell
also notice that linkedqueue.py also implements some simple file handling in its main()

36

You might also like