Code
[('Banana', 10), ('Apple', 2), ('Four Loko', 5)]
DSAN 5500: Data Structures, Objects, and Algorithms in Python
Thursday, February 6, 2025
Today’s Planned Schedule:
| Start | End | Topic | |
|---|---|---|---|
| Lecture | 6:30pm | 7:30pm | HashTable: Linear to Constant Efficiency 🤯 → |
| 7:30pm | 8:00pm | BinarySearchTree: The Final Missing Piece! → |
|
| Break! | 8:00pm | 8:10pm | |
| 8:10pm | 9:00pm | BinarySearchTree: The Final Missing Piece! → |
[('Banana', 10), ('Apple', 2), ('Four Loko', 5)]
\[ T(n) = \overline{O}(1 + \underbrace{\epsilon}_{\mathclap{\text{Collision rate}}} \cdot n) \]
\[ p^{✅} = [T(n) = \overline{O}(1 + \epsilon n)], q^{✅} = [\epsilon \approx 0],\text{ so } p \wedge q \implies T(n) \overset{✅}{=} \overline{O}(1). \]
hash(item) = first letter of item\[ h(\texttt{x}) = \texttt{x[0]} \]
h('Banana') = 'B', h('Monkey') = 'M'item hashes to'Banana'), we compute the hash (B), look in that slot, and obtain the price for bananas.h('Blueberries') = 'B'B slot and see that (Bananas, 10) is already there!!! Wtf do we do here… don’t panic!LinkedList that we can use whenever and however we want!LinkedList? Why not just… another length-26 array, for example?B (or, if we do, we want to be able to expand/contract our price list to handle new/discontinued items)HashTable is an Array that “degenerates into” a LinkedList (when there are collisions)LinkedList) was \(\overline{O}(n)\) for everythihgLinkedListLinkedList! We’ll be able to take our HashMap and “drop in” the BST to play the role LinkedList is playing right nowBST with its \(\overline{O}(\log(n))\) operations, rather than a LinkedList with its \(\overline{O}(n)\) operationsHashMap will go from:
from hw2 import LinkedList, InventoryItem, BinarySearchTree
bst = BinarySearchTree()
item1 = InventoryItem('Mango', 50)
bst.add(item1)
item2 = InventoryItem('Pickle', 60)
bst.add(item2)
item3 = InventoryItem('Artichoke', 55)
bst.add(item3)
item5 = InventoryItem('Banana', 123)
bst.add(item5)
item6 = InventoryItem('Aardvark', 11)
bst.add(item6)
HTML(visualize(bst))collections.abc.Hashable class, such that hash(my_obj) works iff isinstance(my_obj, Hashable)int, str, datetime) come with implementations of ordering, but if you make your own class you need to implement the ordering for it!==, <, >= “Just Work”obj1 < obj2class UtilVector:
def __init__(self, u1, u2):
self.u1 = u1
self.u2 = u2
def __eq__(self, other):
if not isinstance(other, UtilVector):
return NotImplemented
return self.u1 == other.u1 and self.u2 == other.u2
def __ne__(self, other):
if not isinstance(other, UtilVector):
return NotImplemented
return self.u1 != other.u1 or self.u2 != other.u2
def __gt__(self, other):
if not isinstance(other, UtilVector):
return NotImplemented
return self.u1 > other.u1 and self.u2 >= other.u2 or self.u1 >= other.u1 and self.u2 > other.u2
def __ge__(self, other):
return self.__gt__(other) or self.__eq__(other)
def __lt__(self, other):
if not isinstance(other, UtilVector):
return NotImplemented
return other.__gt__(self)
def __le__(self, other):
return self.__lt__(other) or self.__eq__(other)
xA = UtilVector(2, 2)
xB = UtilVector(3, 2)
print(xB > xA)
xC = UtilVector(2, 3)
print(xC > xB)
import itertools
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
x0 = UtilVector(4, 6)
util_vals = np.arange(0, 11, 0.5)
util_pairs = list(itertools.product(util_vals, util_vals))
util_df = pd.DataFrame(util_pairs, columns=['x','y'])
def compare_to_x0(row):
row_vec = UtilVector(row['x'], row['y'])
gt_result = int(row_vec > x0)
lt_result = int(row_vec < x0)
return gt_result - lt_result
util_df['greater'] = util_df.apply(compare_to_x0, axis=1)
#my_palette = sns.color_palette(['#E69F00','lightgray','#CCFFCC'])
my_palette = sns.color_palette(['#FF3535','lightgray','#35FF35'])
sns.relplot(
data=util_df,
x='x', y='y',
hue='greater',
palette=my_palette,
marker='X', s=150
);
x0_df = pd.DataFrame({'x': [4], 'y': [6]})
plt.scatter(data=x0_df, x='x', y='y', color='black')
plt.gca().set_aspect('equal')True
False

InventoryItem classitem_name and price__eq__(other), __ne__(other)__lt__(other), __le__(other), __gt__(other), __ge__(other)__repr__() and __str__()Depth-First Search (DFS)
Breadth-First Search (BFS)
DFS:
InventoryItem[item_name=Mango,price=50]
InventoryItem[item_name=Pickle,price=60]
InventoryItem[item_name=Artichoke,price=55]
InventoryItem[item_name=Banana,price=123]
InventoryItem[item_name=Aardvark,price=11]
BFS:
InventoryItem[item_name=Mango,price=50]
InventoryItem[item_name=Artichoke,price=55]
InventoryItem[item_name=Pickle,price=60]
InventoryItem[item_name=Aardvark,price=11]
InventoryItem[item_name=Banana,price=123]


NodeProcessor, with a single iterate_over(tree) functionThingContainer (could be a stack or a queue, you won’t know which), which has two functions:
put_new_thing_in(new_thing)take_existing_thing_out()| DFS Procedure | Algorithm |
|---|---|
| Pre-Order Traversal | 1. Print node 2. Traverse left subtree 3. Traverse right subtree |
| In-Order Traversal 🧐‼️ | 1. Traverse left subtree 2. Print node 3. Traverse right subtree |
| Post-Order Traversal | 1. Traverse left subtree 2. Traverse right subtree 3. Print node |
h('AA') = 0, h('AB') = 1, …, h('AZ') = 25,h('BA') = 26, h('BB') = 27, …, h('BZ') = 51,h('CA') = 52, …, h('ZZ') = 675.DSAN 5500 Week 5: Binary Search Trees