Skip to content

Commit 8dae29d

Browse files
MengAiDevMengAiDev
authored andcommitted
fix heapdict
1 parent b2798cb commit 8dae29d

File tree

1 file changed

+34
-43
lines changed

1 file changed

+34
-43
lines changed

Lib/collections/__init__.py

Lines changed: 34 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1614,44 +1614,32 @@ def zfill(self, width):
16141614

16151615
import collections.abc
16161616
import heapq
1617-
from typing import Any, Dict, Iterator, List, Optional, Tuple, TypeVar, Union
1617+
import sys
16181618

1619-
K = TypeVar('K')
1620-
V = TypeVar('V')
1619+
# Use string forward references for type annotations to avoid circular imports
1620+
if sys.version_info >= (3, 7):
1621+
from __future__ import annotations
16211622

16221623
class HeapDict(collections.abc.MutableMapping):
16231624
"""Dictionary that maintains heap property based on values.
16241625
16251626
HeapDict combines the functionality of a dictionary with a heap,
16261627
providing efficient access to key-value pairs while maintaining
16271628
a heap property for priority-based operations.
1628-
1629-
Basic operations:
1630-
- d[key] = value: Set a key-value pair
1631-
- value = d[key]: Get value by key
1632-
- del d[key]: Remove a key-value pair
1633-
- key in d: Test if key exists
1634-
- len(d): Get number of items
1635-
- iter(d): Iterate through keys
1636-
1637-
Heap operations:
1638-
- d.popmin(): Remove and return the (key, value) pair with minimum value
1639-
- d.peekmin(): Return the (key, value) pair with minimum value without removing
1640-
- d.update_priority(key, new_value): Update the value/priority of an existing key
16411629
"""
16421630

16431631
def __init__(self, *args, **kwargs):
16441632
"""Initialize a new HeapDict with optional initial values."""
1645-
self._dict: Dict[K, V] = {} # Maps keys to values
1646-
self._heap: List[Tuple[V, K, int]] = [] # List of (value, key, counter)
1633+
self._dict = {} # Maps keys to values
1634+
self._heap = [] # List of (value, key, counter)
16471635
self._counter = 0 # Used to break ties for values that compare equal
16481636
self._removed_keys = set() # Track removed keys for lazy deletion
16491637

16501638
# Add initial items
16511639
if args or kwargs:
16521640
self.update(*args, **kwargs)
16531641

1654-
def __setitem__(self, key: K, value: V) -> None:
1642+
def __setitem__(self, key, value):
16551643
"""Set a key-value pair, maintaining heap property."""
16561644
if key in self._dict:
16571645
self.update_priority(key, value)
@@ -1661,37 +1649,32 @@ def __setitem__(self, key: K, value: V) -> None:
16611649
self._counter += 1
16621650
heapq.heappush(self._heap, (value, key, count))
16631651

1664-
def __getitem__(self, key: K) -> V:
1652+
def __getitem__(self, key):
16651653
"""Get value by key."""
16661654
return self._dict[key]
16671655

1668-
def __delitem__(self, key: K) -> None:
1656+
def __delitem__(self, key):
16691657
"""Remove a key-value pair."""
16701658
if key not in self._dict:
16711659
raise KeyError(key)
16721660

16731661
# Mark the key as removed
16741662
self._removed_keys.add(key)
1675-
1676-
# Remove from dictionary
16771663
del self._dict[key]
1678-
1679-
# Note: We don't remove from the heap here for efficiency.
1680-
# Instead, we do lazy deletion during heap operations.
16811664

1682-
def __iter__(self) -> Iterator[K]:
1665+
def __iter__(self):
16831666
"""Iterate through keys."""
16841667
return iter(self._dict)
16851668

1686-
def __len__(self) -> int:
1669+
def __len__(self):
16871670
"""Return the number of items."""
16881671
return len(self._dict)
16891672

1690-
def __repr__(self) -> str:
1673+
def __repr__(self):
16911674
"""Return string representation."""
16921675
return f"{self.__class__.__name__}({dict(self.items())})"
16931676

1694-
def _clean_heap(self) -> None:
1677+
def _clean_heap(self):
16951678
"""Clean the heap by removing marked items."""
16961679
if len(self._removed_keys) > len(self._heap) // 2:
16971680
# If too many removed items, rebuild the heap
@@ -1700,7 +1683,7 @@ def _clean_heap(self) -> None:
17001683
self._heap = new_heap
17011684
self._removed_keys.clear()
17021685

1703-
def popmin(self) -> Tuple[K, V]:
1686+
def popmin(self):
17041687
"""Remove and return the (key, value) pair with minimum value."""
17051688
if not self._dict:
17061689
raise KeyError("popmin from an empty HeapDict")
@@ -1712,10 +1695,9 @@ def popmin(self) -> Tuple[K, V]:
17121695
del self._dict[key]
17131696
return key, value
17141697

1715-
# This should never happen if the data structure is consistent
17161698
raise RuntimeError("Heap is inconsistent with dictionary")
17171699

1718-
def peekmin(self) -> Tuple[K, V]:
1700+
def peekmin(self):
17191701
"""Return the (key, value) pair with minimum value without removing it."""
17201702
if not self._dict:
17211703
raise KeyError("peekmin from an empty HeapDict")
@@ -1725,29 +1707,38 @@ def peekmin(self) -> Tuple[K, V]:
17251707
value, key, _ = self._heap[0]
17261708
if key not in self._removed_keys and key in self._dict:
17271709
return key, value
1728-
1729-
# If the top item is removed, pop it and continue
17301710
heapq.heappop(self._heap)
17311711

1732-
# This should never happen if the data structure is consistent
17331712
raise RuntimeError("Heap is inconsistent with dictionary")
17341713

1735-
def update_priority(self, key: K, new_value: V) -> None:
1714+
def update_priority(self, key, new_value):
17361715
"""Update the value/priority of an existing key."""
17371716
if key not in self._dict:
17381717
raise KeyError(key)
17391718

17401719
# Update the dictionary
17411720
self._dict[key] = new_value
1742-
1743-
# Mark the old entry as removed
17441721
self._removed_keys.add(key)
1745-
1746-
# Add a new entry to the heap
17471722
count = self._counter
17481723
self._counter += 1
17491724
heapq.heappush(self._heap, (new_value, key, count))
17501725

1751-
# Clean the heap if there are too many removed items
17521726
if len(self._removed_keys) > len(self._heap) // 2:
1753-
self._clean_heap()
1727+
self._clean_heap()
1728+
1729+
# Add type hints for older Python versions or static type checkers
1730+
if sys.version_info < (3, 7) or typing.TYPE_CHECKING:
1731+
from typing import Any, Dict, Iterator, List, Optional, Tuple, TypeVar, Union
1732+
K = TypeVar('K')
1733+
V = TypeVar('V')
1734+
HeapDict.__annotations__ = {
1735+
'_dict': Dict[K, V],
1736+
'_heap': List[Tuple[V, K, int]],
1737+
'__setitem__': None,
1738+
'__getitem__': None,
1739+
'__delitem__': None,
1740+
'__iter__': Iterator[K],
1741+
'popmin': Tuple[K, V],
1742+
'peekmin': Tuple[K, V],
1743+
'update_priority': None
1744+
}

0 commit comments

Comments
 (0)