Leaf node containing key-value pairs. Leaf nodes are where all actual key-value pairs are stored in a B+ tree. They are linked together to form a doubly-linked list for efficient range queries. Attributes: capacity: Maximum number of keys this node can hold. keys: Sorte
| 667 | |
| 668 | |
| 669 | class LeafNode(Node): |
| 670 | """Leaf node containing key-value pairs. |
| 671 | |
| 672 | Leaf nodes are where all actual key-value pairs are stored in a B+ tree. |
| 673 | They are linked together to form a doubly-linked list for efficient range queries. |
| 674 | |
| 675 | Attributes: |
| 676 | capacity: Maximum number of keys this node can hold. |
| 677 | keys: Sorted list of keys. |
| 678 | values: List of values corresponding to keys. |
| 679 | next: Pointer to the next leaf node (for range queries). |
| 680 | """ |
| 681 | |
| 682 | def __init__(self, capacity: int): |
| 683 | self.capacity = capacity |
| 684 | self.keys: List[Any] = [] |
| 685 | self.values: List[Any] = [] |
| 686 | self.next: Optional["LeafNode"] = None # Link to next leaf |
| 687 | |
| 688 | def is_leaf(self) -> bool: |
| 689 | return True |
| 690 | |
| 691 | def is_full(self) -> bool: |
| 692 | return len(self.keys) >= self.capacity |
| 693 | |
| 694 | def __len__(self) -> int: |
| 695 | return len(self.keys) |
| 696 | |
| 697 | def is_underfull(self) -> bool: |
| 698 | """Check if leaf has fewer than minimum required keys.""" |
| 699 | min_keys = (self.capacity - 1) // 2 |
| 700 | return len(self.keys) < min_keys |
| 701 | |
| 702 | def can_donate(self) -> bool: |
| 703 | """Check if leaf can give a key to a sibling (has more than minimum).""" |
| 704 | min_keys = (self.capacity - 1) // 2 |
| 705 | return len(self.keys) > min_keys |
| 706 | |
| 707 | def borrow_from_left(self, left_sibling: "LeafNode") -> None: |
| 708 | """Borrow the rightmost key-value from left sibling""" |
| 709 | if not left_sibling.can_donate(): |
| 710 | raise ValueError("Left sibling cannot donate") |
| 711 | |
| 712 | key = left_sibling.keys.pop() |
| 713 | value = left_sibling.values.pop() |
| 714 | self.keys.insert(0, key) |
| 715 | self.values.insert(0, value) |
| 716 | |
| 717 | def borrow_from_right(self, right_sibling: "LeafNode") -> None: |
| 718 | """Borrow the leftmost key-value from right sibling""" |
| 719 | if not right_sibling.can_donate(): |
| 720 | raise ValueError("Right sibling cannot donate") |
| 721 | |
| 722 | key = right_sibling.keys.pop(0) |
| 723 | value = right_sibling.values.pop(0) |
| 724 | self.keys.append(key) |
| 725 | self.values.append(value) |
| 726 |
no outgoing calls