Skip to content

Commit b4750cf

Browse files
committed
Create SortedTableMap.py
Array Based Map implementation with binary search algorithm based operations for key look ups and iteration methods
1 parent 029f6bc commit b4750cf

File tree

1 file changed

+136
-0
lines changed

1 file changed

+136
-0
lines changed
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
import MapBase
2+
3+
class SortedTableMap(MapBase):
4+
"""Map implementation using a sorted Table"""
5+
6+
#Protected / Private methods
7+
def _find_index(self, k, low, high):
8+
"""Uses the Binary search algorithm and returns the index of the target key,
9+
if item does not exist return index of item is max key
10+
11+
Return index of the left most item with key greater than or equal to k
12+
13+
return high + 1 if no such item qualifies (item with max key in this case)
14+
15+
That is j will be return such that:
16+
all items of slice table[low: j] have key < k
17+
all items of slice table[j: high+1] have key >= k
18+
"""
19+
20+
if high < low:
21+
return high + 1 #if no key qualifies return index of item with max key
22+
else:
23+
#perform binary search
24+
mid= (high+low) //2
25+
if k == self._table[mid]:
26+
return mid
27+
elif k < self._table[mid]:
28+
self._find_index(k, low, mid-1)
29+
else:
30+
self._find_index(k, mid+1, high)
31+
32+
# ---------- Public Methods --------------
33+
def __init__(self):
34+
"""create an empty map as array based sequence (list)"""
35+
self._table=[]
36+
37+
def __len__(self):
38+
"""Return number of items in the map"""
39+
return len(self._table)
40+
41+
def __getitem__(self, k):
42+
"""Return index of (key,value) where k = key, Raise Error if key not found"""
43+
44+
j = self._find_index(self._table, k, 0, len(self._table)-1) # perform binary search for look up and store in j
45+
46+
# if index j is the last index of map or no item in map contains the key at a certain index raise error
47+
if j == len(self._table) or self._table[j]._key != k:
48+
raise KeyError("Key Error: " + repr(k))
49+
50+
return self._table[j]._value # return value assciated with key k if at index j there is a k == key of item at j
51+
52+
def __setitem__(self, k, v):
53+
"""Assign value v to key k, overwriting existin value if another value is present at target k"""
54+
j = self._find_index(k, 0, len(self._table)-1)
55+
56+
if j < len(self._table) and self._table[j]._key == k: # index j that has key == to target k must be less than length of map
57+
self._table[j]._value = v #swap value if item with key k already has a value
58+
else:
59+
self._table.insert(j, self._Item(k,v)) # Add new item at position j
60+
61+
def __delitem__(self, k):
62+
"""Remove Item associated with key k (raise error if key not found in map)"""
63+
j = self._find_index(k, 0, len(self._table)-1)
64+
65+
if j == len(self._table) or self._table[j]._key != k: #if no item has key k for any index j or j is last element in map
66+
raise KeyError("Key Error" + repr(k)) #raise error as key does not exist in map
67+
68+
def __iter__(self):
69+
"""Generate keys of the mpa ordered from minimum to maximum key"""
70+
for item in self._table:
71+
yield item._key
72+
73+
def __reversed__(self):
74+
"""Generate keys of the map from maximum to minimum"""
75+
for item in reversed(self._table):
76+
yield item._key
77+
78+
def find_min(self):
79+
"""Return the item (k,v) where k is the minimum key in map or None if map is empty"""
80+
if len(self._table) > 0:
81+
return (self._table[0]._key, self._table[0]._value)
82+
else:
83+
None
84+
85+
def find_max(self):
86+
"""Return item (k,v) where k is the maximum key in map or None if map is empty"""
87+
if len(self._table)>0:
88+
return (self._table[-1]._key, self._table[-1]._value)
89+
else:
90+
return None
91+
92+
def find_ge(self, k):
93+
"""return (k,v) pair with least key greater than or equal to k"""
94+
j = self._find_index(k, 0, len(self._table)-1) # j's key >= k
95+
96+
if j < len(self._table):
97+
return (self._table[j]._key, self._table[j]._value)
98+
else:
99+
return None
100+
101+
def find_lt(self, k):
102+
"""return (k,v) pair with greatest key strictly smaller than k"""
103+
j = self._find_index(k, 0, len(self._table)-1)
104+
105+
if j < len(self._table):
106+
return (self._table[j-1]._key, self._table[j-1]._value) # j-1 since is greatest key < than k
107+
else:
108+
return None
109+
110+
def find_gt(self, k):
111+
"""Return (key,value) pair with least key strictly greater than k."""
112+
j = self._find_index(k, 0, len(self. table) - 1)
113+
114+
if j < len(self._table) and self._table[j]._key == k:
115+
j+=1
116+
117+
if j < len(self._table):
118+
return (self._table[j]._key, self._table[j]._value)
119+
else:
120+
return None
121+
122+
def find_range(self, start, stop):
123+
"""Iterate through all the (k,v) pairs such that start <= key < stop
124+
125+
if start is None, iterate from item with minimum key until stop
126+
if stop is None, iterate from item at start until the end of the map
127+
"""
128+
129+
if start is None:
130+
j=0
131+
else:
132+
j = self._find_index(start, 0, len(self._table) -1) #find result
133+
134+
while j < len(self._table) and (stop is None or self._table[j]._key < stop):
135+
yield (self._table[j]._key, self._table[j]._value)
136+
j+=1

0 commit comments

Comments
 (0)