๐Ÿ—จLanguage/Python

[Python] heapq ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ

์—ฌ์šฐ๋น„_YoBi 2024. 8. 7. 20:30
ํž™ํ(heapq)๋Š” ํŒŒ์ด์ฌ ํ‘œ์ค€๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ์ œ๊ณตํ•˜๋Š” ๋ชจ๋“ˆ๋กœ Heap ์ž๋ฃŒ๊ตฌ์กฐ๋ฅผ ์ง€์›ํ•œ๋‹ค. 
์™„์ „ ์ด์ง„ํŠธ๋ฆฌ ํ˜•ํƒœ๋ฅผ ํ•˜๊ณ  ์žˆ์œผ๋ฉฐ, ์ตœ์†Ÿ๊ฐ’๊ณผ ์ตœ๋Œ“๊ฐ’์„ ๋น ๋ฅด๊ฒŒ ์ฐพ์„ ์ˆ˜ ์žˆ๋‹ค . 
ํŒŒ์ด์ฌ์€ ๊ธฐ๋ณธ์ ์œผ๋กœ ์ตœ์†Œํž™(min-heap)์„ ์ œ๊ณตํ•œ๋‹ค. (๋ถ€๋ชจ ๋…ธ๋“œ์˜ ๊ฐ’์€ ์ž์‹ ๋…ธ๋“œ์˜ ๊ฐ’๋ณด๋‹ค ์ž‘๊ฑฐ๋‚˜ ๊ฐ™๋‹ค.)

์ฃผ์š” ๋ฉ”์†Œ๋“œ

heapq.heappush(heap, item)

ํž™์˜ ์กฐ๊ฑด์„ ์œ ์ง€ํ•˜๋ฉด์„œ item์„ heap์— push ํ•ด์ค€๋‹ค. ( O(logn) )

import heapq

heap = []

for i in range(10):
    heapq.heappush(heap, i)
print(heap)

## [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

heapq.heappop(heap)

ํž™์—์„œ ๊ฐ€์žฅ ์ž‘์€ ์š”์†Œ๋ฅผ ์ œ๊ฑฐํ•˜๊ณ  ๋ฐ˜ํ™˜ํ•จ.  ( O(logn) )

ํž™์ด ๋น„์–ด์žˆ์œผ๋ฉด IndexError์„ ๋ฐœ์ƒ์‹œํ‚ด

import heapq

heap = [3,4,5,6]

print(heapq.heappop(heap))
### 3
print(heap)
### [4, 6, 5]

heapq.heapify(list)

๋ฆฌ์ŠคํŠธ๋ฅผ ํž™์œผ๋กœ ๋ณ€ํ™˜์‹œํ‚ด ( O(n) )

๋ฆฌ์ŠคํŠธ๋ฅผ ์ตœ์†Œ ํž™ ์†์„ฑ์„ ๊ฐ€์ง€๋„๋ก ์ •๋ ฌํ•จ. 

import heapq

list = [3,6,34,3,5,7,3,6,24,143]

heapq.heapify(list)

print(list)
##[3, 3, 3, 6, 5, 7, 34, 6, 24, 143]

heapq.nlargest ( n, heap, key=None )

heap์—์„œ ๊ฐ€์žฅ ํฐ n ๊ฐœ์˜ ์š”์†Œ๋ฅผ ๋ฐ˜ํ™˜ํ•จ. ( O(nlogn) )

key๋ฅผ ํ†ตํ•ด ์ •๋ ฌ๊ธฐ์ค€์„ ์ •ํ•  ์ˆ˜ ์žˆ๋‹ค. 

import heapq
heap = []
for i in range(10):
    heapq.heappush(heap, i)

print(heapq.nlargest(3,heap))
## [9, 8, 7]

 

heapq.nsmallest(n, heap, key=None)

heap์—์„œ ๊ฐ€์žฅ ์ž‘์€ n๊ฐœ์˜ ์š”์†Œ๋ฅผ ๋ฐ˜ํ™˜( O(nlogn) )

key๋ฅผ ํ†ตํ•ด ๊ธฐ์ค€ ์„ค์ • ๊ฐ€๋Šฅ

import heapq
heap = []
for i in range(10):
    heapq.heappush(heap, i)

print(heapq.nsmallest(3,heap))
#[0, 1, 2]

ํ™œ์šฉ ์˜ˆ์‹œ

1. ์ตœ๋Œ€ ํž™ ๊ตฌํ˜„

import heapq

heap = []
number = [4,3,2,3,1]

for num in number:
	heapq.heappush(heap, -num) #[-4, -3, -3, -2, -1]

for _ in range(len(heap)):
	print(-heapq.heappop(heap), end = ", ")

## 4 3 3 2 1

ํŒŒ์ด์ฌ์—์„œ๋Š” ์ตœ๋Œ€ ํž™์„ ์ œ๊ณตํ•˜์ง€ ์•Š๋Š”๋‹ค. 

ํž™์— ๋ถ€ํ˜ธ๋ฅผ ๋ณ€๊ฒฝํ•˜์—ฌ ๊ฐ’์„ ๋„ฃ์–ด์ฃผ๋ฉด ๊ฐ„์ ‘์ ์œผ๋กœ ์ตœ๋Œ€ ํž™์„ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค. 

2. ์ค‘์•™ ๊ฐ’ ์ฐพ๊ธฐ

import heapq

class MedianFinder:
    def __init__(self):
        self.left_heap = []  # ์ตœ๋Œ€ ํž™
        self.right_heap = []  # ์ตœ์†Œ ํž™

    def add_num(self, num):
        # ์ตœ๋Œ€ ํž™์— ์ถ”๊ฐ€ 
        heapq.heappush(self.left_heap, -num)
        
        # ์ตœ๋Œ€ ํž™์˜ ์ตœ๋Œ€๊ฐ’์„ ์ตœ์†Œ ํž™์— ์ด๋™
        heapq.heappush(self.right_heap, -heapq.heappop(self.left_heap))
        
        # ์ตœ์†Œ ํž™์˜ ํฌ๊ธฐ๊ฐ€ ๋” ์ปค์ง€๋ฉด ์ตœ์†Œ ํž™์˜ ์ตœ์†Œ๊ฐ’์„ ์ตœ๋Œ€ ํž™์œผ๋กœ ์ด๋™
        if len(self.right_heap) > len(self.left_heap):
            heapq.heappush(self.left_heap, -heapq.heappop(self.right_heap))

    def find_median(self):
        if len(self.left_heap) > len(self.right_heap):
            return -self.left_heap[0]
        else:
            return min(-self.left_heap[0], self.right_heap[0])


medianFinder = MedianFinder()
numbers = [4,1,3,4,5,6,4,3,3]

for num in numbers:
    medianFinder.add_num(num)
    print(f"Inserted {num}, current median is: {medianFinder.find_median()}")
    
"""
Inserted 4, current median is: 4
Inserted 1, current median is: 1
Inserted 3, current median is: 3
Inserted 4, current median is: 3
Inserted 5, current median is: 4
Inserted 6, current median is: 4
Inserted 4, current median is: 4
Inserted 3, current median is: 4
Inserted 3, current median is: 4
"""

์ตœ๋Œ€ ํž™๊ณผ ์ตœ์†Œ ํž™์„ ํ™œ์šฉํ•˜์—ฌ ์ค‘์•™ ๊ฐ’ ์ฐพ๋Š” ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค.