def floor(self, key: Key): r = self.rank(key) if r >= len(self._items): return self.max() if r == 0 and not eq(self._items[r].key, key): return None return self._items[r].key if eq(self._items[r].key, key) else self._items[r - 1].key
def delete(self, key): # no node with the given key exists in the tree if self.get(key) is None: return parent = None is_node_left_child = False node = self._root while node is not None: if eq(key, node.key): break parent = node # this is why we want to make sure that the key must exist in the tree. parent.node_count = parent.node_count - 1 if lt(key, node.key): node = node.left is_node_left_child = True else: node = node.right is_node_left_child = False successor, parent_of_successor = self._find_successor_and_parent(node) if successor is None: # the deleted node has no right subtree if parent is None: # the deleted node is the current root self._root = node.left elif is_node_left_child: parent.left = node.left else: parent.right = node.left else: # replace successor by its right child # Note: Because the successor is the left-most node, it can either have no child or only one right child, # and it must be its parent's left child. if parent_of_successor is not None: parent_of_successor.left = successor.right # replace the deleted node by its successor if parent is None: # the deleted node is the current root self._root = successor elif is_node_left_child: parent.left = successor else: parent.right = successor successor.left = node.left # the successor is the node's right child if it is the only node in the node's right subtree, # and we want to avoid cycle here. if not eq(successor, node.right): successor.right = node.right if successor is not None: successor.node_count = node.node_count - 1 if parent_of_successor is not None: parent_of_successor.node_count = parent_of_successor.node_count - 1
def ceiling(self, key: Key): r = self.rank(key) if r >= len(self._items): return None if r == 0 and not eq(self._items[r].key, key): return self.min() return self._items[r].key
def _rank(self, key, node): if node is None: return 0 left_child_count = node.left.node_count if node.left is not None else 0 if eq(key, node.key): return left_child_count if gt(key, node.key): return 1 + left_child_count + self._rank(key, node.right) return self._rank(key, node.left)
def put(self, key: Key, value): r = self.rank(key) if r >= len(self._items): self._items.append(KeyValue(key, value)) elif eq(self._items[r].key, key): self._items[r].value = value else: shift_right(self._items, r) self._items[r] = KeyValue(key, value)
def get(self, key) -> Optional[Node]: if self.is_empty(): return None current = self._root while current is not None: if eq(current.key, key): return current current = current.left if lt(key, current.key) else current.right return None
def _ceiling(self, key, node): if node is None: return None if eq(key, node.key): return node if gt(key, node.key): return self._ceiling(key, node.right) left_subtree_ceiling = self._ceiling(key, node.left) return left_subtree_ceiling if left_subtree_ceiling is not None else node
def _floor(self, key, node): if node is None: return None if eq(key, node.key): return node if lt(key, node.key): return self._floor(key, node.left) right_subtree_floor = self._floor(key, node.right) return right_subtree_floor if right_subtree_floor is not None else node
def binary_search(items, item): low = 0 high = len(items) - 1 while high >= low: mid = int(floor((high + low) / 2)) if eq(items[mid], item): return mid if gt(item, items[mid]): low = mid + 1 else: high = mid - 1 return None
def range(self, low: Key = None, high: Key = None): rank_of_low = self.rank(low) if low is not None else 0 rank_of_high = self.rank(high) if high is not None else len( self._items) - 1 if rank_of_low > rank_of_high: return [] result = [] for i in range(rank_of_low, rank_of_high): result.append(self._items[i].key) if high is None or (0 <= rank_of_high < len(self._items) and eq(self._items[rank_of_high].key, high)): result.append(self._items[rank_of_high].key) return result
def _put(self, new_node: Node, position: Node): if position is None: return new_node if eq(new_node.key, position.key): position.value = new_node.value return position if lt(new_node.key, position.key): position.left = self._put(new_node, position.left) else: position.right = self._put(new_node, position.right) position.node_count = (position.left.node_count if position.left is not None else 0) \ + (position.right.node_count if position.right is not None else 0) \ + 1 return position
def has_same_items(l1, l2): """ This implementation takes O(n*log(n)) time mainly for sorting the two lists before comparing their items. Another implementation would be to loop over the first list, build a hash table from that list, and then loop over the second list to check if any item not in the hash table. Note that we also need to keep track of the item count to handle duplicated items. This implementation takes O(n) time. """ if len(l1) != len(l2): return False sorted_l1 = quick_sort(l1) sorted_l2 = quick_sort(l2) for i in range(len(sorted_l1)): if not eq(sorted_l1[i], sorted_l2[i]): return False return True
def rank(self, key: Key): low = 0 high = len(self._items) - 1 while high >= low: mid = int(floor(high + low) / 2) if eq(key, self._items[mid].key): return mid if mid + 1 < len(self._items) and gt( key, self._items[mid].key) and lt( key, self._items[mid + 1].key): return mid + 1 if gt(key, self._items[mid].key): low = mid + 1 else: high = mid - 1 if low >= len(self._items): return len(self._items) if high < 0: return 0
def _index_of_key(self, key): r = self.rank(key) return r if r < len(self._items) and eq(self._items[r].key, key) else None
def equals(self, other): return eq(self.value, other.value)
def equals(self, other): return eq(self.key, other.key)
def test_check_equals(self): assert eq(None, None) assert not eq(1, 2) assert eq(2, 2) assert not eq(2, 1) assert not eq(1.1, 1.2) assert not eq(2.1, 1.9) assert eq(2.1, 2.1) assert not eq(KeyValue(1), KeyValue(2)) assert eq(KeyValue(2), KeyValue(2)) assert not eq(KeyValue(2), KeyValue(1)) assert not eq(KeyValue(Key(1)), KeyValue(Key(2))) assert eq(KeyValue(Key(2)), KeyValue(Key(2))) assert not eq(KeyValue(Key(2)), KeyValue(Key(1)))