MCS 275 Spring 2024
Emily Dumas
Reminders and announcements:
IntegerSetBase
- non-functional base class; declares interface, does type checking, just needs a storage system to be addedIntegerSet
- uses BSTIntegerSetUL
- uses unsorted listIntegerSetSL
- uses sorted listintegerset.py
has been updated with a script to test addition and membership test times
for 20,000 integers.
Back to discussing binary trees (BST or not).
To systematically visit every node is to traverse or walk the tree.
Natural to do recursively; think of it as three tasks:
Result depends on how you order the tasks.
preorder means: | Node, | Left, | Right |
postorder means: | Left, | Right, | Node |
inorder means: | Left, | Node, | Right |
Note: They all visit left child before right child.
node, left, right
Typical use: Make a copy of the tree.
Insert the keys into an empty BST in this order to recreate the original tree.
left, right, node
Typical use: Delete the tree.
If you delete keys in postorder, then you will only ever be removing nodes without children.
left, node, right
Typical use: Turn a BST into a sorted list of keys.
Many different binary trees can have the same inorder traversal.
Many different binary trees can have the same preorder traversal.
And yet:
Theorem: A binary tree T
is uniquely determined by its inorder and
preorder traversals.
MCS 360 usually covers rebalancing operations.
Python's built-in type set
represents an unordered collection of distinct objects.
You can put an object in a set
if (and only if) it's allowed as a key of a
dict
. For built-in types that usually just means immutable.
Allowed: bool, int, float, str, tuple
Not allowed: list, set, dict
S = { 4, 8, 15, 16, 23, 42 } # Set literal
S = set() # New empty set
S.add(5) # S is {5}
S.add(10) # S is {5,10}
8 in S # False
5 in S # True
S.discard(1) # Does nothing
S.remove(1) # Raises KeyError
S.remove(5) # Now S is {10}
S.pop() # Remove and return one element (unclear which!)
for x in S: # sets are iterable (but no control over order)
print(x)
Binary operations returning new sets:
S | S2 # Evaluates to union of sets
S & S2 # Evaluates to intersection of sets
S.union(iterable) # Like | but allows any iterable
S.intersection(iterable) # Like & but allows any iterable
Operations that modify a set S
based on contents of another collection.
# adds elements of iterable to S
S.update(iterable)
# remove anything from S that is NOT in the iterable
S.intersection_update(iterable)
# remove anything from S that is in the iterable
S.difference_update(iterable)
set
has lots of other features that are described in the documentation.
Python's set
is basically a dictionary without values.
For large collections, it is much faster than using a list.
Appropriate whenever order is not important, and items cannot appear multiple times.
You want to know how many times each character appears in a string.
hist = dict()
for c in s:
hist[c] += 1
This won't work. Why?
Built-in module collections
contains a class defaultdict
that works like a
dictionary, but
if a key is requested that doesn't exist, it creates it and assigns a default value.
import collections
hist = collections.defaultdict(int)
for c in s:
hist[c] += 1
This works!
The defaultdict
constructor takes one argument, a function default_factory
.
default_factory
is called to make default values for keys when needed.
Common examples with built-in factories:
defaultdict(list) # default value [] as returned by list()
defaultdict(int) # default value 0, as returned by int()
defaultdict(float) # default value 0.0, as returned by float()
defaultdict(str) # default value "", as returned by str()