In [ ]:
%%HTML
<style>
.container { width: 100% }
</style>
The class ListNode
implements a node of a linked lists of
key-value pairs. Every node has three member variables:
mKey
stores the key,mValue
stores the value associated with this key, andmNextPtr
stores a reference to the next node. If there is no next node, then
mNextPtr
is None
.Objects of class ListNode
are used to represent linked lists.
The constructor of the class ListNode
creates a single node that stores the given key
and its associated value
.
In [ ]:
class ListNode:
def __init__(self, key, value):
self.mKey = key
self.mValue = value
self.mNextPtr = None
Given a key
, the method find
traverses the given list until it finds a node that stores the given key
. In this case, it returns the associated value. Otherwise, None
is returned.
In [ ]:
def find(self, key):
ptr = self
while True:
if ptr.mKey == key:
return ptr.mValue
if ptr.mNextPtr != None:
ptr = ptr.mNextPtr
else:
return
ListNode.find = find
del find
Given the first node of a linked list $L$, the function $L.\texttt{insert}(k, v)$ inserts the key-value pair $(k, v)$ into the list $L$. If there is already a key value pair in $L$ that has the same key, then the old value is overwritten. It returns a boolean that is true if a new node has been allocated.
In [ ]:
def insert(self, key, value):
while True:
if self.mKey == key:
self.mValue = value
return False
elif self.mNextPtr != None:
self = self.mNextPtr
else:
self.mNextPtr = ListNode(key, value)
return True
ListNode.insert = insert
del insert
Given the first node of a linked list $L$, the function $L.\texttt{delete}(k)$ deletes the first key-value pair of the form $(k, v)$ from the list $L$. If there is no such pair, the list $L$ is unchanged. It returns a pair.
None
.True
if a node has been deleted.
In [ ]:
def delete(self, key):
previous = None
ptr = self
while True:
if ptr.mKey == key:
if previous == None:
return ptr.mNextPtr, True
else:
previous.mNextPtr = ptr.mNextPtr
return self, True
elif ptr.mNextPtr != None:
previous = ptr
ptr = ptr.mNextPtr
else:
break
return self, False
ListNode.delete = delete
del delete
Given the first node of a linked list $L$, the function $L.\texttt{toString}()$ returns a string representing $L$.
In [ ]:
def toString(self):
if self.mNextPtr != None:
return f'{self.mKey} ↦ {self.mValue}, ' + self.mNextPtr.__str__()
else:
return f'{self.mKey} ↦ {self.mValue}'
ListNode.__str__ = toString
del toString
The class ListMap
implements a map using a linked list of key-value pairs. Basically, it is a wrapper for the class
ListNode
. Furthermore, an object of type ListMap
is iterable.
In [ ]:
class ListMap:
def __init__(self):
self.mPtr = None
def find(self, key):
if self.mPtr != None:
return self.mPtr.find(key)
def insert(self, key, value):
if self.mPtr != None:
return self.mPtr.insert(key, value)
else:
self.mPtr = ListNode(key, value)
return True
def delete(self, key):
if self.mPtr != None:
newPtr, flag = self.mPtr.delete(key)
self.mPtr = newPtr
return flag
return False
def __iter__(self):
return MapIterator(self.mPtr)
def __str__(self):
if self.mPtr != None:
return '{' + self.mPtr.__str__() + '}'
else:
return '{}'
def __repr__(self):
return self.__str__()
A MapIterator
is an iterator that iterates over the elements of a linked list.
In [ ]:
class MapIterator:
def __init__(self, ptr):
self.mPtr = ptr
def __next__(self):
if self.mPtr == None:
raise StopIteration
key = self.mPtr.mKey
value = self.mPtr.mValue
self.mPtr = self.mPtr.mNextPtr
return key, value
In [ ]:
def main(n = 100):
S = ListMap()
for i in range(2, n + 1):
S.insert(i, True)
for i in range(2, n // 2 + 1):
for j in range(i, n // i + 1):
S.delete(i * j)
print([p for p, _ in S])
print(S.find(83))
print(S.find(99))
In [ ]:
main()
In [ ]: