Skip to content

Commit 4e58c1c

Browse files
authored
Merge pull request #166 from BrianLusina/feat/algorithms-design-continuous-median
feat(algorithms design, data-structures): continuous median
2 parents abfe9cb + 156e4d5 commit 4e58c1c

File tree

3 files changed

+60
-0
lines changed

3 files changed

+60
-0
lines changed

DIRECTORY.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -588,6 +588,8 @@
588588
* [Visitor](https://github.com/BrianLusina/PythonSnips/blob/master/design_patterns/behavioral/visitor/visitor.py)
589589
* Browser History
590590
* [Test Browser History](https://github.com/BrianLusina/PythonSnips/blob/master/design_patterns/browser_history/test_browser_history.py)
591+
* Continuous Median
592+
* [Test Continuous Median Handler](https://github.com/BrianLusina/PythonSnips/blob/master/design_patterns/continuous_median/test_continuous_median_handler.py)
591593
* Linked List
592594
* [Test Linked List](https://github.com/BrianLusina/PythonSnips/blob/master/design_patterns/linked_list/test_linked_list.py)
593595
* Oop
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)