Skip to content

Commit 9f635dc

Browse files
committed
feat(algorithms, design, heaps): continuous median
1 parent abfe9cb commit 9f635dc

File tree

2 files changed

+58
-0
lines changed

2 files changed

+58
-0
lines changed
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
from typing import Optional
2+
import heapq
3+
4+
5+
class ContinuousMedianHandler:
6+
def __init__(self):
7+
self.median: Optional[int | float] = None
8+
# Max heap keeps track of the lower half of numbers
9+
self.max_heap = []
10+
# Min Heap keeps track of the upper half of numbers
11+
self.min_heap = []
12+
13+
def insert(self, number: int) -> None:
14+
heapq.heappush(self.min_heap, -heapq.heappushpop(self.max_heap, -number))
15+
16+
if len(self.min_heap) - len(self.max_heap) > 1:
17+
heapq.heappush(self.max_heap, -heapq.heappop(self.min_heap))
18+
19+
if len(self.max_heap) == len(self.min_heap):
20+
max_heap_root = self.max_heap[0]
21+
min_heap_root = self.min_heap[0]
22+
median = (min_heap_root - max_heap_root) / 2
23+
self.median = median
24+
else:
25+
self.median = self.min_heap[0]
26+
27+
def get_median(self) -> Optional[int | float]:
28+
return self.median
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import unittest
2+
from typing import List, Tuple
3+
from parameterized import parameterized
4+
from design_patterns.continuous_median import ContinuousMedianHandler
5+
6+
CONTINUOUS_MEDIA_HANDLER_TESTS = [
7+
(
8+
([(1, 2), 1.50000], [(3), 2.00000]),
9+
),
10+
]
11+
12+
13+
class ContinuousMedianHandlerTestCase(unittest.TestCase):
14+
@parameterized.expand(CONTINUOUS_MEDIA_HANDLER_TESTS)
15+
def test_continuous_median_handler(self, requests: List[Tuple[List[Tuple[int]] | int, int | float]]):
16+
median_handler = ContinuousMedianHandler()
17+
for request in requests:
18+
data, expected = request
19+
if type(data) is int:
20+
median_handler.insert(data)
21+
else:
22+
for d in data:
23+
median_handler.insert(d)
24+
25+
actual = median_handler.get_median()
26+
self.assertEqual(expected, actual)
27+
28+
29+
if __name__ == "__main__":
30+
unittest.main()

0 commit comments

Comments
 (0)