Skip to content

Latest commit

ย 

History

History

C_05_Heap

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
ย 
ย 

README.md

Heap (ํž™)

๋ชฉ์ฐจ

  1. ๊ฐœ๋… ๋ฐ ์ •์˜
  2. ํž™์˜ ์ข…๋ฅ˜
  3. ํž™์˜ ๊ตฌ์กฐ
  4. Python heapq ๋ชจ๋“ˆ
  5. ์ตœ๋Œ€ ํž™ ๊ตฌํ˜„
  6. ์šฐ์„ ์ˆœ์œ„ ํ
  7. ๊ตฌํ˜„ ์ฝ”๋“œ
  8. ์‹ค์ „ ๋ฌธ์ œ
  9. ํž™ ๋ฌธ์ œ ์œ ํ˜• ์ •๋ฆฌ
  10. ์‹œ๊ฐ„๋ณต์žก๋„

1. ๊ฐœ๋… ๋ฐ ์ •์˜

1.1 ํž™์ด๋ž€?

ํž™(Heap)์€ ์™„์ „ ์ด์ง„ ํŠธ๋ฆฌ ๊ธฐ๋ฐ˜์˜ ์ž๋ฃŒ๊ตฌ์กฐ๋กœ, ํŠธ๋ฆฌ์—์„œ ์ตœ๋Œ€/์ตœ์†Œ๊ฐ’์„ ๋น ๋ฅด๊ฒŒ ๊ตฌํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

ํž™ = ์šฐ์„ ์ˆœ์œ„ ํ๋ฅผ ๊ตฌํ˜„ํ•˜๊ธฐ ์œ„ํ•œ ์™„์ „ ์ด์ง„ ํŠธ๋ฆฌ

1.2 ํž™์˜ ํŠน์ง•

  • ์™„์ „ ์ด์ง„ ํŠธ๋ฆฌ: ๋งˆ์ง€๋ง‰ ๋ ˆ๋ฒจ์„ ์ œ์™ธํ•œ ๋ชจ๋“  ๋ ˆ๋ฒจ์ด ์ฑ„์›Œ์ ธ ์žˆ๊ณ , ๋งˆ์ง€๋ง‰ ๋ ˆ๋ฒจ์€ ์™ผ์ชฝ๋ถ€ํ„ฐ ์ฑ„์›Œ์ง
  • ํž™ ์†์„ฑ: ๋ถ€๋ชจ์™€ ์ž์‹ ์‚ฌ์ด์— ๋Œ€์†Œ ๊ด€๊ณ„ ์œ ์ง€
  • ์ตœ๋Œ€/์ตœ์†Œ๊ฐ’ ์ ‘๊ทผ: O(1)
  • ์‚ฝ์ž…/์‚ญ์ œ: O(log n)

1.3 ์ผ์ƒ ์† ํž™์˜ ์˜ˆ

์˜ˆ์‹œ ์„ค๋ช…
์‘๊ธ‰์‹ค ๋Œ€๊ธฐ ๊ฐ€์žฅ ์œ„๊ธ‰ํ•œ ํ™˜์ž๊ฐ€ ๋จผ์ € ์น˜๋ฃŒ
์ž‘์—… ์Šค์ผ€์ค„๋ง ์šฐ์„ ์ˆœ์œ„ ๋†’์€ ์ž‘์—…๋ถ€ํ„ฐ ์ฒ˜๋ฆฌ
๋„คํŠธ์›Œํฌ ํŒจํ‚ท ์ค‘์š”๋„์— ๋”ฐ๋ผ ํŒจํ‚ท ์ฒ˜๋ฆฌ
๊ฒŒ์ž„ AI ๊ฐ€์žฅ ์œ„ํ˜‘์ ์ธ ์ ์„ ๋จผ์ € ๊ณต๊ฒฉ

1.4 ํž™ vs ์ด์ง„ ํƒ์ƒ‰ ํŠธ๋ฆฌ

ํŠน์„ฑ ํž™ (Heap) BST (์ด์ง„ ํƒ์ƒ‰ ํŠธ๋ฆฌ)
๋ชฉ์  ์ตœ๋Œ€/์ตœ์†Œ ๋น ๋ฅธ ์ ‘๊ทผ ์ •๋ ฌ๋œ ๋ฐ์ดํ„ฐ ์œ ์ง€
์ •๋ ฌ ๋ถ€๋ชจ > ์ž์‹ (๋˜๋Š” <) ์™ผ์ชฝ < ๋ถ€๋ชจ < ์˜ค๋ฅธ์ชฝ
๊ตฌ์กฐ ์™„์ „ ์ด์ง„ ํŠธ๋ฆฌ ์ด์ง„ ํŠธ๋ฆฌ
์ตœ๋Œ€/์ตœ์†Œ ์ ‘๊ทผ O(1) O(log n) ~ O(n)
ํƒ์ƒ‰ O(n) O(log n) ํ‰๊ท 

2. ํž™์˜ ์ข…๋ฅ˜

2.1 ์ตœ๋Œ€ ํž™ (Max Heap)

์ตœ๋Œ€ ํž™: ๋ถ€๋ชจ ๋…ธ๋“œ โ‰ฅ ์ž์‹ ๋…ธ๋“œ

             100
            /    \
          90      80
         /  \    /  \
        70  60  50  40

ํŠน์ง•:
- ๋ฃจํŠธ๊ฐ€ ์ตœ๋Œ€๊ฐ’
- ๋ถ€๋ชจ๋Š” ํ•ญ์ƒ ์ž์‹๋ณด๋‹ค ํฌ๊ฑฐ๋‚˜ ๊ฐ™์Œ
- ํ˜•์ œ ์‚ฌ์ด์—๋Š” ๋Œ€์†Œ ๊ด€๊ณ„ ์—†์Œ

2.2 ์ตœ์†Œ ํž™ (Min Heap)

์ตœ์†Œ ํž™: ๋ถ€๋ชจ ๋…ธ๋“œ โ‰ค ์ž์‹ ๋…ธ๋“œ

              10
            /    \
          20      30
         /  \    /  \
        40  50  60  70

ํŠน์ง•:
- ๋ฃจํŠธ๊ฐ€ ์ตœ์†Œ๊ฐ’
- ๋ถ€๋ชจ๋Š” ํ•ญ์ƒ ์ž์‹๋ณด๋‹ค ์ž‘๊ฑฐ๋‚˜ ๊ฐ™์Œ
- ํ˜•์ œ ์‚ฌ์ด์—๋Š” ๋Œ€์†Œ ๊ด€๊ณ„ ์—†์Œ

2.3 ๋น„๊ต ํ‘œ

๊ตฌ๋ถ„ ์ตœ๋Œ€ ํž™ (Max Heap) ์ตœ์†Œ ํž™ (Min Heap)
์กฐ๊ฑด ๋ถ€๋ชจ โ‰ฅ ์ž์‹ ๋ถ€๋ชจ โ‰ค ์ž์‹
๋ฃจํŠธ ์ตœ๋Œ€๊ฐ’ ์ตœ์†Œ๊ฐ’
์šฉ๋„ ๋‚ด๋ฆผ์ฐจ์ˆœ ์ •๋ ฌ, ์ตœ๋Œ€๊ฐ’ ๋ฐ˜๋ณต ์ถ”์ถœ ์˜ค๋ฆ„์ฐจ์ˆœ ์ •๋ ฌ, ์ตœ์†Œ๊ฐ’ ๋ฐ˜๋ณต ์ถ”์ถœ
Python ์Œ์ˆ˜ ๋ณ€ํ™˜ ํ•„์š” heapq ๊ธฐ๋ณธ

3. ํž™์˜ ๊ตฌ์กฐ

3.1 ๋ฐฐ์—ด๋กœ ํž™ ํ‘œํ˜„

์™„์ „ ์ด์ง„ ํŠธ๋ฆฌ๋Š” ๋ฐฐ์—ด๋กœ ํšจ์œจ์ ์œผ๋กœ ํ‘œํ˜„ ๊ฐ€๋Šฅ

์ตœ์†Œ ํž™ ์˜ˆ์‹œ:
            10
          /    \
        20      30
       /  \    /
      40  50  60

๋ฐฐ์—ด: [10, 20, 30, 40, 50, 60]
์ธ๋ฑ์Šค: 0   1   2   3   4   5

์ธ๋ฑ์Šค ๊ด€๊ณ„ (0-based):
- ๋ถ€๋ชจ: (i - 1) // 2
- ์™ผ์ชฝ ์ž์‹: 2 * i + 1
- ์˜ค๋ฅธ์ชฝ ์ž์‹: 2 * i + 2

3.2 ํž™ ์—ฐ์‚ฐ ๊ณผ์ •

์‚ฝ์ž… (Insert) - Heapify Up

์‚ฝ์ž… ๊ณผ์ • (์ตœ์†Œ ํž™์— 5 ์‚ฝ์ž…):

1. ๋งˆ์ง€๋ง‰ ์œ„์น˜์— ์‚ฝ์ž…
            10                    10
          /    \                /    \
        20      30    โ†’       20      30
       /  \    /  \          /  \    /  \
      40  50  60  [5]       40  50  60   5

2. ๋ถ€๋ชจ์™€ ๋น„๊ตํ•˜๋ฉฐ ์œ„๋กœ ์ด๋™ (Heapify Up)
            10                    10                     5
          /    \                /    \                 /    \
        20      30    โ†’       20       5     โ†’       20      10
       /  \    /  \          /  \    /  \           /  \    /  \
      40  50  60   5        40  50  60  30         40  50  60  30

๊ฒฐ๊ณผ: 5๊ฐ€ ๋ฃจํŠธ๋กœ ์ด๋™

์‚ญ์ œ (Delete) - Heapify Down

์‚ญ์ œ ๊ณผ์ • (์ตœ์†Œ ํž™์—์„œ ๋ฃจํŠธ ์‚ญ์ œ):

1. ๋ฃจํŠธ(์ตœ์†Œ๊ฐ’) ๋ฐ˜ํ™˜, ๋งˆ์ง€๋ง‰ ๋…ธ๋“œ๋ฅผ ๋ฃจํŠธ๋กœ ์ด๋™
             5                    30
          /    \                /    \
        20      10    โ†’       20      10
       /  \    /              /  \
      40  50  30             40  50

2. ์ž์‹๊ณผ ๋น„๊ตํ•˜๋ฉฐ ์•„๋ž˜๋กœ ์ด๋™ (Heapify Down)
            30                    10
          /    \                /    \
        20      10    โ†’       20      30
       /  \                  /  \
      40  50                40  50

๊ฒฐ๊ณผ: 10์ด ๋ฃจํŠธ๋กœ ์ด๋™

4. Python heapq ๋ชจ๋“ˆ

4.1 heapq ์†Œ๊ฐœ

Python์˜ heapq ๋ชจ๋“ˆ์€ **์ตœ์†Œ ํž™(Min Heap)**์„ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค.

import heapq

# ๊ธฐ๋ณธ ์‚ฌ์šฉ๋ฒ•
heap = []                    # ๋นˆ ํž™ ์ƒ์„ฑ
heapq.heappush(heap, 3)     # ์‚ฝ์ž…
heapq.heappush(heap, 1)
heapq.heappush(heap, 2)
print(heap)                  # [1, 3, 2]

min_val = heapq.heappop(heap)  # ์ตœ์†Œ๊ฐ’ ์ถ”์ถœ
print(min_val)               # 1
print(heap)                  # [2, 3]

4.2 heapq ์ฃผ์š” ํ•จ์ˆ˜

ํ•จ์ˆ˜ ์„ค๋ช… ์‹œ๊ฐ„๋ณต์žก๋„
heappush(heap, item) ์›์†Œ ์‚ฝ์ž… O(log N)
heappop(heap) ์ตœ์†Œ๊ฐ’ ์ œ๊ฑฐ ๋ฐ ๋ฐ˜ํ™˜ O(log N)
heapify(list) ๋ฆฌ์ŠคํŠธ๋ฅผ ํž™์œผ๋กœ ๋ณ€ํ™˜ O(N)
heappushpop(heap, item) push ํ›„ pop (ํšจ์œจ์ ) O(log N)
heapreplace(heap, item) pop ํ›„ push (ํšจ์œจ์ ) O(log N)
nsmallest(n, iterable) ๊ฐ€์žฅ ์ž‘์€ n๊ฐœ ๋ฐ˜ํ™˜ O(N log n)
nlargest(n, iterable) ๊ฐ€์žฅ ํฐ n๊ฐœ ๋ฐ˜ํ™˜ O(N log n)

4.3 ํ•จ์ˆ˜๋ณ„ ์ƒ์„ธ ์„ค๋ช… ๋ฐ ์˜ˆ์ œ

4.3.1 heappush(heap, item)

import heapq

heap = []
heapq.heappush(heap, 5)
heapq.heappush(heap, 3)
heapq.heappush(heap, 8)
heapq.heappush(heap, 1)

print(heap)  # [1, 3, 8, 5]
# ์ฐธ๊ณ : ๋‚ด๋ถ€ ๋ฐฐ์—ด ์ˆœ์„œ์™€ ์ •๋ ฌ ์ˆœ์„œ๋Š” ๋‹ค๋ฆ„
# ํ•˜์ง€๋งŒ heappop() ํ•˜๋ฉด ํ•ญ์ƒ ์ตœ์†Œ๊ฐ’์ด ๋‚˜์˜ด

4.3.2 heappop(heap)

import heapq

heap = [1, 3, 8, 5]
heapq.heapify(heap)  # ํž™ ๊ตฌ์กฐ ๋ณด์žฅ

min_val = heapq.heappop(heap)
print(min_val)  # 1
print(heap)     # [3, 5, 8]

# ์—ฐ์† pop์œผ๋กœ ์ •๋ ฌ๋œ ์ˆœ์„œ ์–ป๊ธฐ
heap = [5, 3, 8, 1, 2]
heapq.heapify(heap)
sorted_list = [heapq.heappop(heap) for _ in range(len(heap))]
print(sorted_list)  # [1, 2, 3, 5, 8]

4.3.3 heapify(list)

import heapq

# ๊ธฐ์กด ๋ฆฌ์ŠคํŠธ๋ฅผ ํž™์œผ๋กœ ๋ณ€ํ™˜
numbers = [5, 3, 8, 1, 2, 7]
heapq.heapify(numbers)  # O(N)
print(numbers)  # [1, 2, 7, 5, 3, 8]

# ์ฃผ์˜: heapify๋Š” in-place๋กœ ๋ณ€ํ™˜
# ์ƒˆ ๋ฆฌ์ŠคํŠธ๋ฅผ ๋ฐ˜ํ™˜ํ•˜์ง€ ์•Š์Œ

4.3.4 heappushpop(heap, item)

import heapq

# push ํ›„ pop (push + pop๋ณด๋‹ค ํšจ์œจ์ )
heap = [1, 3, 5, 7]
result = heapq.heappushpop(heap, 2)
print(result)  # 1 (์ตœ์†Œ๊ฐ’ ๋ฐ˜ํ™˜)
print(heap)    # [2, 3, 5, 7]

# ์‚ฌ์šฉ ์˜ˆ: ์ƒ์œ„ k๊ฐœ๋งŒ ์œ ์ง€
def top_k_smallest(nums, k):
    return heapq.nsmallest(k, nums)

4.3.5 heapreplace(heap, item)

import heapq

# pop ํ›„ push (pop + push๋ณด๋‹ค ํšจ์œจ์ )
heap = [1, 3, 5, 7]
result = heapq.heapreplace(heap, 10)
print(result)  # 1 (๋จผ์ € pop๋œ ๊ฐ’)
print(heap)    # [3, 7, 5, 10]

# ์ฃผ์˜: heapreplace๋Š” ๋นˆ ํž™์—์„œ ์—๋Ÿฌ ๋ฐœ์ƒ

4.3.6 nsmallest / nlargest

import heapq

numbers = [5, 3, 8, 1, 2, 7, 9, 4]

# ๊ฐ€์žฅ ์ž‘์€ 3๊ฐœ
smallest_3 = heapq.nsmallest(3, numbers)
print(smallest_3)  # [1, 2, 3]

# ๊ฐ€์žฅ ํฐ 3๊ฐœ
largest_3 = heapq.nlargest(3, numbers)
print(largest_3)  # [9, 8, 7]

# ํ‚ค ํ•จ์ˆ˜ ์‚ฌ์šฉ
students = [
    {'name': 'Kim', 'score': 85},
    {'name': 'Lee', 'score': 92},
    {'name': 'Park', 'score': 78}
]

# ์ ์ˆ˜ ๊ธฐ์ค€ ์ƒ์œ„ 2๋ช…
top_2 = heapq.nlargest(2, students, key=lambda x: x['score'])
print(top_2)
# [{'name': 'Lee', 'score': 92}, {'name': 'Kim', 'score': 85}]

4.4 ํž™ peek (์ตœ์†Œ๊ฐ’ ํ™•์ธ๋งŒ)

import heapq

heap = [1, 3, 5, 7]

# peek: ์ œ๊ฑฐ ์—†์ด ์ตœ์†Œ๊ฐ’ ํ™•์ธ
min_val = heap[0]  # O(1)
print(min_val)  # 1
print(heap)     # [1, 3, 5, 7] (๋ณ€๊ฒฝ ์—†์Œ)

# ์ฃผ์˜: heap[1]์ด ๋‘ ๋ฒˆ์งธ๋กœ ์ž‘์€ ๊ฐ’์€ ์•„๋‹˜!
# ๋‘ ๋ฒˆ์งธ ์ตœ์†Œ๊ฐ’์„ ์•Œ๋ ค๋ฉด pop ํ›„ ๋‹ค์‹œ peek

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

5.1 ์Œ์ˆ˜ ๋ณ€ํ™˜ ๋ฐฉ์‹

Python์˜ heapq๋Š” ์ตœ์†Œ ํž™๋งŒ ์ง€์›ํ•˜๋ฏ€๋กœ, ์ตœ๋Œ€ ํž™์€ ์Œ์ˆ˜(-) ๋ณ€ํ™˜์œผ๋กœ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค.

import heapq

# ์ตœ๋Œ€ ํž™ ๊ตฌํ˜„: ์Œ์ˆ˜๋กœ ์ €์žฅํ•˜๊ณ  ์Œ์ˆ˜๋กœ ๊บผ๋‚ด๊ธฐ
max_heap = []

# ์‚ฝ์ž…: ์Œ์ˆ˜๋กœ ์ €์žฅ
heapq.heappush(max_heap, -5)
heapq.heappush(max_heap, -3)
heapq.heappush(max_heap, -8)
heapq.heappush(max_heap, -1)

print(max_heap)  # [-8, -3, -5, -1]

# ์ถ”์ถœ: ์Œ์ˆ˜๋ฅผ ๋‹ค์‹œ ์–‘์ˆ˜๋กœ
max_val = -heapq.heappop(max_heap)
print(max_val)  # 8 (์ตœ๋Œ€๊ฐ’)

# ์ตœ๋Œ€๊ฐ’ ํ™•์ธ (peek)
max_peek = -max_heap[0]
print(max_peek)  # 5

5.2 ์ตœ๋Œ€ ํž™ ๋ž˜ํผ ํ•จ์ˆ˜

import heapq

class MaxHeap:
    """์ตœ๋Œ€ ํž™ ๋ž˜ํผ ํด๋ž˜์Šค"""

    def __init__(self):
        self.heap = []

    def push(self, val):
        """๊ฐ’ ์‚ฝ์ž… (์Œ์ˆ˜๋กœ ๋ณ€ํ™˜)"""
        heapq.heappush(self.heap, -val)

    def pop(self):
        """์ตœ๋Œ€๊ฐ’ ์ถ”์ถœ (์–‘์ˆ˜๋กœ ๋ณ€ํ™˜)"""
        return -heapq.heappop(self.heap)

    def peek(self):
        """์ตœ๋Œ€๊ฐ’ ํ™•์ธ"""
        return -self.heap[0]

    def __len__(self):
        return len(self.heap)

    def __bool__(self):
        return bool(self.heap)

# ์‚ฌ์šฉ ์˜ˆ์‹œ
max_heap = MaxHeap()
max_heap.push(5)
max_heap.push(3)
max_heap.push(8)
max_heap.push(1)

print(max_heap.peek())  # 8
print(max_heap.pop())   # 8
print(max_heap.pop())   # 5

5.3 ํŠœํ”Œ์„ ์ด์šฉํ•œ ๋ฐฉ๋ฒ•

import heapq

# (์šฐ์„ ์ˆœ์œ„, ๊ฐ’) ํŠœํ”Œ ์‚ฌ์šฉ
# ์šฐ์„ ์ˆœ์œ„๊ฐ€ ๊ฐ™์œผ๋ฉด ๊ฐ’์œผ๋กœ ๋น„๊ต

# ์ตœ์†Œ ํž™ (๊ธฐ๋ณธ)
min_heap = []
heapq.heappush(min_heap, (1, 'low'))
heapq.heappush(min_heap, (3, 'high'))
heapq.heappush(min_heap, (2, 'medium'))

print(heapq.heappop(min_heap))  # (1, 'low')

# ์ตœ๋Œ€ ํž™ (์šฐ์„ ์ˆœ์œ„์— ์Œ์ˆ˜)
max_heap = []
heapq.heappush(max_heap, (-1, 'low'))
heapq.heappush(max_heap, (-3, 'high'))
heapq.heappush(max_heap, (-2, 'medium'))

priority, value = heapq.heappop(max_heap)
print(-priority, value)  # 3 high

6. ์šฐ์„ ์ˆœ์œ„ ํ

6.1 ์šฐ์„ ์ˆœ์œ„ ํ๋ž€?

์šฐ์„ ์ˆœ์œ„ ํ(Priority Queue)๋Š” ์šฐ์„ ์ˆœ์œ„์— ๋”ฐ๋ผ ์š”์†Œ๊ฐ€ ์ฒ˜๋ฆฌ๋˜๋Š” ํ์ž…๋‹ˆ๋‹ค.

  • ์ผ๋ฐ˜ ํ: FIFO (์„ ์ž…์„ ์ถœ)
  • ์šฐ์„ ์ˆœ์œ„ ํ: ์šฐ์„ ์ˆœ์œ„ ๋†’์€ ๊ฒƒ์ด ๋จผ์ € ์ถœ๋ ฅ

6.2 ํž™์œผ๋กœ ์šฐ์„ ์ˆœ์œ„ ํ ๊ตฌํ˜„

import heapq

class PriorityQueue:
    """ํž™ ๊ธฐ๋ฐ˜ ์šฐ์„ ์ˆœ์œ„ ํ"""

    def __init__(self):
        self.heap = []
        self.count = 0  # ๋™์ผ ์šฐ์„ ์ˆœ์œ„ ์ฒ˜๋ฆฌ์šฉ

    def push(self, item, priority):
        """
        ์•„์ดํ…œ ์‚ฝ์ž…
        priority๊ฐ€ ์ž‘์„์ˆ˜๋ก ๋†’์€ ์šฐ์„ ์ˆœ์œ„ (์ตœ์†Œ ํž™)
        """
        # (์šฐ์„ ์ˆœ์œ„, ์‚ฝ์ž…์ˆœ์„œ, ์•„์ดํ…œ) - ๋™์ผ ์šฐ์„ ์ˆœ์œ„๋ฉด ์‚ฝ์ž… ์ˆœ์„œ๋กœ
        heapq.heappush(self.heap, (priority, self.count, item))
        self.count += 1

    def pop(self):
        """๊ฐ€์žฅ ๋†’์€ ์šฐ์„ ์ˆœ์œ„ ์•„์ดํ…œ ์ถ”์ถœ"""
        if self.heap:
            return heapq.heappop(self.heap)[2]  # item๋งŒ ๋ฐ˜ํ™˜
        return None

    def peek(self):
        """๊ฐ€์žฅ ๋†’์€ ์šฐ์„ ์ˆœ์œ„ ์•„์ดํ…œ ํ™•์ธ"""
        if self.heap:
            return self.heap[0][2]
        return None

    def is_empty(self):
        return len(self.heap) == 0

# ์‚ฌ์šฉ ์˜ˆ์‹œ
pq = PriorityQueue()
pq.push('์น˜๋ฃŒ', 1)      # ๋†’์€ ์šฐ์„ ์ˆœ์œ„
pq.push('์˜ˆ๋ฐฉ์ ‘์ข…', 3)   # ๋‚ฎ์€ ์šฐ์„ ์ˆœ์œ„
pq.push('๊ฒ€์ง„', 2)       # ์ค‘๊ฐ„ ์šฐ์„ ์ˆœ์œ„

print(pq.pop())  # ์น˜๋ฃŒ
print(pq.pop())  # ๊ฒ€์ง„
print(pq.pop())  # ์˜ˆ๋ฐฉ์ ‘์ข…

6.3 Python queue.PriorityQueue

from queue import PriorityQueue

# PriorityQueue ์‚ฌ์šฉ (์Šค๋ ˆ๋“œ ์•ˆ์ „)
pq = PriorityQueue()

pq.put((1, '๊ธด๊ธ‰'))
pq.put((3, '๋ณดํ†ต'))
pq.put((2, '์ค‘์š”'))

print(pq.get())  # (1, '๊ธด๊ธ‰')
print(pq.get())  # (2, '์ค‘์š”')
print(pq.get())  # (3, '๋ณดํ†ต')

# ์ฃผ์˜: heapq๊ฐ€ ๋” ๋น ๋ฆ„ (์Šค๋ ˆ๋“œ ์•ˆ์ „ ์˜ค๋ฒ„ํ—ค๋“œ ์—†์Œ)
# ๋‹จ์ผ ์Šค๋ ˆ๋“œ ์ฝ”๋”ฉํ…Œ์ŠคํŠธ์—์„œ๋Š” heapq ๊ถŒ์žฅ

7. ๊ตฌํ˜„ ์ฝ”๋“œ

7.1 ์ง์ ‘ ํž™ ๊ตฌํ˜„ (๊ต์œก์šฉ)

class MinHeap:
    """์ตœ์†Œ ํž™ ์ง์ ‘ ๊ตฌํ˜„ (๊ต์œก์šฉ)"""

    def __init__(self):
        self.heap = []

    def parent(self, i):
        return (i - 1) // 2

    def left_child(self, i):
        return 2 * i + 1

    def right_child(self, i):
        return 2 * i + 2

    def swap(self, i, j):
        self.heap[i], self.heap[j] = self.heap[j], self.heap[i]

    def push(self, val):
        """์‚ฝ์ž… ํ›„ heapify up"""
        self.heap.append(val)
        self._heapify_up(len(self.heap) - 1)

    def _heapify_up(self, i):
        """์œ„๋กœ ์ด๋™ํ•˜๋ฉฐ ํž™ ์†์„ฑ ์œ ์ง€"""
        while i > 0 and self.heap[self.parent(i)] > self.heap[i]:
            self.swap(i, self.parent(i))
            i = self.parent(i)

    def pop(self):
        """์ตœ์†Œ๊ฐ’ ์ถ”์ถœ ํ›„ heapify down"""
        if not self.heap:
            return None

        min_val = self.heap[0]
        last = self.heap.pop()

        if self.heap:
            self.heap[0] = last
            self._heapify_down(0)

        return min_val

    def _heapify_down(self, i):
        """์•„๋ž˜๋กœ ์ด๋™ํ•˜๋ฉฐ ํž™ ์†์„ฑ ์œ ์ง€"""
        smallest = i
        left = self.left_child(i)
        right = self.right_child(i)

        if left < len(self.heap) and self.heap[left] < self.heap[smallest]:
            smallest = left

        if right < len(self.heap) and self.heap[right] < self.heap[smallest]:
            smallest = right

        if smallest != i:
            self.swap(i, smallest)
            self._heapify_down(smallest)

    def peek(self):
        return self.heap[0] if self.heap else None

    def __len__(self):
        return len(self.heap)

# ์‚ฌ์šฉ ์˜ˆ์‹œ
heap = MinHeap()
heap.push(5)
heap.push(3)
heap.push(8)
heap.push(1)

print(heap.pop())  # 1
print(heap.pop())  # 3
print(heap.pop())  # 5
print(heap.pop())  # 8

7.2 ์ฝ”๋”ฉํ…Œ์ŠคํŠธ์šฉ ๊ฐ„๋‹จ ๊ตฌํ˜„

import heapq

# ์ตœ์†Œ ํž™ (๊ธฐ๋ณธ)
min_heap = []
heapq.heappush(min_heap, 3)
heapq.heappush(min_heap, 1)
heapq.heappush(min_heap, 2)

while min_heap:
    print(heapq.heappop(min_heap))  # 1, 2, 3

# ์ตœ๋Œ€ ํž™ (์Œ์ˆ˜ ๋ณ€ํ™˜)
max_heap = []
for val in [3, 1, 2]:
    heapq.heappush(max_heap, -val)

while max_heap:
    print(-heapq.heappop(max_heap))  # 3, 2, 1

# ๋ฆฌ์ŠคํŠธ๋ฅผ ํž™์œผ๋กœ ๋ณ€ํ™˜
nums = [5, 3, 8, 1, 2]
heapq.heapify(nums)  # O(n)
print(nums)  # [1, 2, 8, 5, 3]

8. ์‹ค์ „ ๋ฌธ์ œ

8.1 ๋ฌธ์ œ 1: K๋ฒˆ์งธ ํฐ ์š”์†Œ (LeetCode 215)

๋ฌธ์ œ ์„ค๋ช…

์ •์ˆ˜ ๋ฐฐ์—ด nums์™€ ์ •์ˆ˜ k๊ฐ€ ์ฃผ์–ด์งˆ ๋•Œ,
๋ฐฐ์—ด์—์„œ k๋ฒˆ์งธ๋กœ ํฐ ์š”์†Œ๋ฅผ ๋ฐ˜ํ™˜ํ•˜์‹œ์˜ค.

์˜ˆ์‹œ:
nums = [3,2,1,5,6,4], k = 2
return = 5 (์ •๋ ฌํ•˜๋ฉด [6,5,4,3,2,1]์—์„œ 2๋ฒˆ์งธ)

์ •๋‹ต ์ฝ”๋“œ

import heapq

def findKthLargest(nums, k):
    """
    ๋ฐฉ๋ฒ• 1: ์ตœ๋Œ€ ํž™ ์‚ฌ์šฉ
    - ๋ชจ๋“  ์š”์†Œ๋ฅผ ์ตœ๋Œ€ ํž™์— ๋„ฃ๊ณ  k๋ฒˆ pop
    """
    max_heap = [-x for x in nums]
    heapq.heapify(max_heap)

    for _ in range(k - 1):
        heapq.heappop(max_heap)

    return -heapq.heappop(max_heap)

def findKthLargest_v2(nums, k):
    """
    ๋ฐฉ๋ฒ• 2: ์ตœ์†Œ ํž™์œผ๋กœ k๊ฐœ๋งŒ ์œ ์ง€
    - ํฌ๊ธฐ k์˜ ์ตœ์†Œ ํž™ ์œ ์ง€
    - ํž™์˜ ๋ฃจํŠธ๊ฐ€ k๋ฒˆ์งธ ํฐ ๊ฐ’
    """
    min_heap = nums[:k]
    heapq.heapify(min_heap)

    for num in nums[k:]:
        if num > min_heap[0]:
            heapq.heapreplace(min_heap, num)

    return min_heap[0]

# ํ…Œ์ŠคํŠธ
print(findKthLargest([3,2,1,5,6,4], 2))  # 5
print(findKthLargest([3,2,3,1,2,4,5,5,6], 4))  # 4

8.2 ๋ฌธ์ œ 2: ๋” ๋งต๊ฒŒ (ํ”„๋กœ๊ทธ๋ž˜๋จธ์Šค)

๋ฌธ์ œ ์„ค๋ช…

๋ชจ๋“  ์Œ์‹์˜ ์Šค์ฝ”๋นŒ ์ง€์ˆ˜๋ฅผ K ์ด์ƒ์œผ๋กœ ๋งŒ๋“ค์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
์Šค์ฝ”๋นŒ ์ง€์ˆ˜๊ฐ€ ๊ฐ€์žฅ ๋‚ฎ์€ ๋‘ ์Œ์‹์„ ์„ž์–ด ์ƒˆ๋กœ์šด ์Œ์‹์„ ๋งŒ๋“ญ๋‹ˆ๋‹ค.
์ƒˆ ์Œ์‹์˜ ์Šค์ฝ”๋นŒ = ๊ฐ€์žฅ ๋‚ฎ์€ ์Œ์‹ + (๋‘ ๋ฒˆ์งธ๋กœ ๋‚ฎ์€ ์Œ์‹ * 2)
๋ชจ๋“  ์Œ์‹์˜ ์Šค์ฝ”๋นŒ ์ง€์ˆ˜๊ฐ€ K ์ด์ƒ์ด ๋  ๋•Œ๊นŒ์ง€ ๋ฐ˜๋ณตํ•ฉ๋‹ˆ๋‹ค.
๋ช‡ ๋ฒˆ ์„ž์–ด์•ผ ํ•˜๋Š”์ง€ returnํ•˜์‹œ์˜ค.

์˜ˆ์‹œ:
scoville = [1, 2, 3, 9, 10, 12], K = 7
return = 2

์ •๋‹ต ์ฝ”๋“œ

import heapq

def solution(scoville, K):
    """
    ๋” ๋งต๊ฒŒ - ์ตœ์†Œ ํž™ ํ™œ์šฉ

    ์ „๋žต:
    1. ์Šค์ฝ”๋นŒ ์ง€์ˆ˜๋ฅผ ์ตœ์†Œ ํž™์œผ๋กœ ๊ด€๋ฆฌ
    2. ์ตœ์†Œ๊ฐ’์ด K ๋ฏธ๋งŒ์ด๋ฉด ๋‘ ๊ฐœ ๊บผ๋‚ด์„œ ์„ž๊ธฐ
    3. ๋” ์ด์ƒ ์„ž์„ ์ˆ˜ ์—†์œผ๋ฉด -1 ๋ฐ˜ํ™˜
    """
    heapq.heapify(scoville)  # O(n)
    count = 0

    while scoville[0] < K:
        if len(scoville) < 2:
            return -1  # ๋” ์ด์ƒ ์„ž์„ ์ˆ˜ ์—†์Œ

        # ๊ฐ€์žฅ ์•ˆ ๋งค์šด ๊ฒƒ ๋‘ ๊ฐœ ๊บผ๋‚ด๊ธฐ
        first = heapq.heappop(scoville)
        second = heapq.heappop(scoville)

        # ์„ž๊ธฐ
        new_scoville = first + second * 2
        heapq.heappush(scoville, new_scoville)

        count += 1

    return count

# ํ…Œ์ŠคํŠธ
print(solution([1, 2, 3, 9, 10, 12], 7))  # 2

8.3 ๋ฌธ์ œ 3: ๋””์Šคํฌ ์ปจํŠธ๋กค๋Ÿฌ (ํ”„๋กœ๊ทธ๋ž˜๋จธ์Šค)

๋ฌธ์ œ ์„ค๋ช…

ํ•˜๋“œ๋””์Šคํฌ๊ฐ€ ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•  ๋•Œ, ์š”์ฒญ์ด ๋“ค์–ด์˜จ ์ˆœ์„œ๋Œ€๋กœ ์ฒ˜๋ฆฌํ•˜์ง€ ์•Š๊ณ 
ํ˜„์žฌ ์‹œ์ ์—์„œ ๊ฐ€์žฅ ์งง์€ ์ž‘์—…๋ถ€ํ„ฐ ์ฒ˜๋ฆฌํ•˜๋ฉด ํ‰๊ท  ๋Œ€๊ธฐ ์‹œ๊ฐ„์„ ์ค„์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

jobs[i] = [์š”์ฒญ ์‹œ์ , ์†Œ์š” ์‹œ๊ฐ„]
๋ชจ๋“  ์š”์ฒญ์˜ ํ‰๊ท  ๋ฐ˜ํ™˜ ์‹œ๊ฐ„์„ ์ตœ์†Œํ™”ํ•˜์‹œ์˜ค.

์˜ˆ์‹œ:
jobs = [[0, 3], [1, 9], [2, 6]]
return = 9

์ •๋‹ต ์ฝ”๋“œ

import heapq

def solution(jobs):
    """
    ๋””์Šคํฌ ์ปจํŠธ๋กค๋Ÿฌ - SJF (Shortest Job First)

    ์ „๋žต:
    1. ํ˜„์žฌ ์‹œ์ ์—์„œ ์ฒ˜๋ฆฌ ๊ฐ€๋Šฅํ•œ ์ž‘์—… ์ค‘ ๊ฐ€์žฅ ์งง์€ ๊ฒƒ ์„ ํƒ
    2. ์ตœ์†Œ ํž™์œผ๋กœ ์†Œ์š” ์‹œ๊ฐ„ ๊ธฐ์ค€ ๊ด€๋ฆฌ
    """
    jobs.sort(key=lambda x: x[0])  # ์š”์ฒญ ์‹œ์  ์ˆœ ์ •๋ ฌ
    n = len(jobs)

    heap = []  # (์†Œ์š” ์‹œ๊ฐ„, ์š”์ฒญ ์‹œ์ )
    total_time = 0
    current_time = 0
    job_index = 0

    while job_index < n or heap:
        # ํ˜„์žฌ ์‹œ์ ๊นŒ์ง€ ๋„์ฐฉํ•œ ์ž‘์—…์„ ํž™์— ์ถ”๊ฐ€
        while job_index < n and jobs[job_index][0] <= current_time:
            heapq.heappush(heap, (jobs[job_index][1], jobs[job_index][0]))
            job_index += 1

        if heap:
            # ๊ฐ€์žฅ ์งง์€ ์ž‘์—… ์ฒ˜๋ฆฌ
            duration, arrival = heapq.heappop(heap)
            current_time += duration
            total_time += current_time - arrival  # ๋ฐ˜ํ™˜ ์‹œ๊ฐ„
        else:
            # ์ฒ˜๋ฆฌํ•  ์ž‘์—…์ด ์—†์œผ๋ฉด ๋‹ค์Œ ์ž‘์—… ์‹œ์ ์œผ๋กœ ์ด๋™
            current_time = jobs[job_index][0]

    return total_time // n

# ํ…Œ์ŠคํŠธ
print(solution([[0, 3], [1, 9], [2, 6]]))  # 9

8.4 ๋ฌธ์ œ 4: ์ด์ค‘ ์šฐ์„ ์ˆœ์œ„ ํ (ํ”„๋กœ๊ทธ๋ž˜๋จธ์Šค)

๋ฌธ์ œ ์„ค๋ช…

์ด์ค‘ ์šฐ์„ ์ˆœ์œ„ ํ๋Š” ๋‹ค์Œ ์—ฐ์‚ฐ์„ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค:
- I ์ˆซ์ž: ํ์— ์ฃผ์–ด์ง„ ์ˆซ์ž ์‚ฝ์ž…
- D 1: ์ตœ๋Œ€๊ฐ’ ์‚ญ์ œ
- D -1: ์ตœ์†Œ๊ฐ’ ์‚ญ์ œ

๋ชจ๋“  ์—ฐ์‚ฐ์„ ์ฒ˜๋ฆฌํ•œ ํ›„ ํ๊ฐ€ ๋น„์–ด์žˆ์œผ๋ฉด [0, 0]
๋น„์–ด์žˆ์ง€ ์•Š์œผ๋ฉด [์ตœ๋Œ€๊ฐ’, ์ตœ์†Œ๊ฐ’] ๋ฐ˜ํ™˜

์˜ˆ์‹œ:
operations = ["I 16", "I -5643", "D -1", "D 1", "D 1", "I 123", "D -1"]
return = [0, 0]

์ •๋‹ต ์ฝ”๋“œ

import heapq

def solution(operations):
    """
    ์ด์ค‘ ์šฐ์„ ์ˆœ์œ„ ํ

    ์ „๋žต:
    ์ตœ์†Œ ํž™๊ณผ ์ตœ๋Œ€ ํž™ ๋™์‹œ ๊ด€๋ฆฌ + ์‚ญ์ œ ์—ฌ๋ถ€ ์ถ”์ 
    """
    min_heap = []
    max_heap = []
    entry_count = {}  # ์œ ํšจํ•œ ์š”์†Œ ์ถ”์ 

    for op in operations:
        cmd, val = op.split()
        val = int(val)

        if cmd == 'I':
            heapq.heappush(min_heap, val)
            heapq.heappush(max_heap, -val)
            entry_count[val] = entry_count.get(val, 0) + 1

        elif cmd == 'D':
            # ์œ ํšจํ•˜์ง€ ์•Š์€ ์š”์†Œ ์ œ๊ฑฐ
            while min_heap and entry_count.get(min_heap[0], 0) == 0:
                heapq.heappop(min_heap)
            while max_heap and entry_count.get(-max_heap[0], 0) == 0:
                heapq.heappop(max_heap)

            if val == 1 and max_heap:  # ์ตœ๋Œ€๊ฐ’ ์‚ญ์ œ
                max_val = -heapq.heappop(max_heap)
                entry_count[max_val] -= 1
            elif val == -1 and min_heap:  # ์ตœ์†Œ๊ฐ’ ์‚ญ์ œ
                min_val = heapq.heappop(min_heap)
                entry_count[min_val] -= 1

    # ์œ ํšจํ•˜์ง€ ์•Š์€ ์š”์†Œ ์ •๋ฆฌ
    while min_heap and entry_count.get(min_heap[0], 0) == 0:
        heapq.heappop(min_heap)
    while max_heap and entry_count.get(-max_heap[0], 0) == 0:
        heapq.heappop(max_heap)

    if not min_heap:
        return [0, 0]

    return [-max_heap[0], min_heap[0]]

# ํ…Œ์ŠคํŠธ
print(solution(["I 16", "D 1"]))  # [0, 0]
print(solution(["I 7", "I 5", "I -5", "D -1"]))  # [7, 5]

8.5 ๋ฌธ์ œ 5: ๋‹ค์ต์ŠคํŠธ๋ผ ์•Œ๊ณ ๋ฆฌ์ฆ˜ (ํž™ ํ™œ์šฉ)

import heapq

def dijkstra(graph, start):
    """
    ๋‹ค์ต์ŠคํŠธ๋ผ ์•Œ๊ณ ๋ฆฌ์ฆ˜ - ํž™ ํ™œ์šฉ

    graph: {๋…ธ๋“œ: [(๊ฑฐ๋ฆฌ, ์—ฐ๊ฒฐ๋…ธ๋“œ), ...]}
    """
    distances = {node: float('inf') for node in graph}
    distances[start] = 0

    heap = [(0, start)]  # (๊ฑฐ๋ฆฌ, ๋…ธ๋“œ)

    while heap:
        current_dist, current_node = heapq.heappop(heap)

        # ์ด๋ฏธ ์ฒ˜๋ฆฌ๋œ ๋…ธ๋“œ๋ฉด ์Šคํ‚ต
        if current_dist > distances[current_node]:
            continue

        for dist, neighbor in graph[current_node]:
            new_dist = current_dist + dist

            if new_dist < distances[neighbor]:
                distances[neighbor] = new_dist
                heapq.heappush(heap, (new_dist, neighbor))

    return distances

# ์˜ˆ์‹œ
graph = {
    'A': [(1, 'B'), (4, 'C')],
    'B': [(2, 'C'), (5, 'D')],
    'C': [(1, 'D')],
    'D': []
}
print(dijkstra(graph, 'A'))
# {'A': 0, 'B': 1, 'C': 3, 'D': 4}

9. ํž™ ๋ฌธ์ œ ์œ ํ˜• ์ •๋ฆฌ

9.1 ํž™์œผ๋กœ ํ’€์–ด์•ผ ํ•˜๋Š” ์œ ํ˜•

ํ‚ค์›Œ๋“œ ํ™•๋ฅ  ์„ค๋ช…
"์ตœ๋Œ€/์ตœ์†Œ ๋นˆ๋ฒˆ" ๋†’์Œ ์ตœ๋Œ€๊ฐ’ ๋˜๋Š” ์ตœ์†Œ๊ฐ’์„ ๋ฐ˜๋ณต์ ์œผ๋กœ ๊ตฌํ•จ
"K๋ฒˆ์งธ" ๋†’์Œ K๋ฒˆ์งธ ํฐ/์ž‘์€ ๊ฐ’
"์šฐ์„ ์ˆœ์œ„" ๋†’์Œ ์šฐ์„ ์ˆœ์œ„์— ๋”ฐ๋ฅธ ์ฒ˜๋ฆฌ
"๋‹ค์ต์ŠคํŠธ๋ผ" 100% ์ตœ๋‹จ ๊ฒฝ๋กœ ์•Œ๊ณ ๋ฆฌ์ฆ˜
"์ƒ์œ„ K๊ฐœ" ๋†’์Œ ๊ฐ€์žฅ ํฐ/์ž‘์€ K๊ฐœ ์š”์†Œ
"์ •๋ ฌ + ์ค‘๊ฐ„" ์ค‘๊ฐ„ ์ค‘๊ฐ„๊ฐ’ ์ฐพ๊ธฐ (๋‘ ๊ฐœ์˜ ํž™ ์‚ฌ์šฉ)

9.2 ํž™ ๋ฌธ์ œ ํŒ๋ณ„๋ฒ•

๋ฌธ์ œ์—์„œ ๋‹ค์Œ ํŒจํ„ด์ด ๋ณด์ด๋ฉด ํž™์„ ๊ณ ๋ คํ•˜์„ธ์š”:

1. ์ตœ๋Œ€/์ตœ์†Œ๊ฐ’์„ ์—ฌ๋Ÿฌ ๋ฒˆ ๊ตฌํ•ด์•ผ ํ•˜๋Š” ๋ฌธ์ œ
   โ†’ ๋งค๋ฒˆ ์ •๋ ฌํ•˜๋ฉด ๋น„ํšจ์œจ์ , ํž™ ์‚ฌ์šฉ

2. K๋ฒˆ์งธ ์š”์†Œ๋ฅผ ์ฐพ๋Š” ๋ฌธ์ œ
   โ†’ ํž™์œผ๋กœ K๊ฐœ๋งŒ ์œ ์ง€

3. ์šฐ์„ ์ˆœ์œ„ ๊ธฐ๋ฐ˜ ์ฒ˜๋ฆฌ
   โ†’ ์šฐ์„ ์ˆœ์œ„ ํ๋กœ ๊ตฌํ˜„

4. ๋™์ ์œผ๋กœ ์ •๋ ฌ ์ƒํƒœ๋ฅผ ์œ ์ง€ํ•ด์•ผ ํ•˜๋Š” ๋ฌธ์ œ
   โ†’ ์‚ฝ์ž…/์‚ญ์ œ ํ›„์—๋„ ์ตœ๋Œ€/์ตœ์†Œ ๋น ๋ฅด๊ฒŒ ์ ‘๊ทผ

5. ๋‹ค์ต์ŠคํŠธ๋ผ, ํ”„๋ฆผ ์•Œ๊ณ ๋ฆฌ์ฆ˜
   โ†’ ํž™ ๊ธฐ๋ฐ˜ ๊ตฌํ˜„์ด ํšจ์œจ์ 

9.3 ๋Œ€ํ‘œ์ ์ธ ํž™ ๋ฌธ์ œ๋“ค

๋ฌธ์ œ ์œ ํ˜• ์˜ˆ์‹œ
K๋ฒˆ์งธ ์š”์†Œ K๋ฒˆ์งธ ํฐ ์ˆ˜, ์ƒ์œ„ K๊ฐœ
ํ•ฉ์น˜๊ธฐ ๋” ๋งต๊ฒŒ, ๋Œ ํ•ฉ์น˜๊ธฐ
์Šค์ผ€์ค„๋ง ๋””์Šคํฌ ์ปจํŠธ๋กค๋Ÿฌ, ์ž‘์—… ์Šค์ผ€์ค„๋ง
์ตœ๋‹จ ๊ฒฝ๋กœ ๋‹ค์ต์ŠคํŠธ๋ผ, ํ”„๋ฆผ
์ค‘๊ฐ„๊ฐ’ ์ŠคํŠธ๋ฆฌ๋ฐ ์ค‘๊ฐ„๊ฐ’
์ด์ค‘ ํž™ ์ด์ค‘ ์šฐ์„ ์ˆœ์œ„ ํ

10. ์‹œ๊ฐ„๋ณต์žก๋„

10.1 ํž™ ์—ฐ์‚ฐ ์‹œ๊ฐ„๋ณต์žก๋„

์—ฐ์‚ฐ ์‹œ๊ฐ„๋ณต์žก๋„ ์„ค๋ช…
heappush O(log N) ์‚ฝ์ž… ํ›„ heapify up
heappop O(log N) ์ œ๊ฑฐ ํ›„ heapify down
heapify O(N) ๋ฆฌ์ŠคํŠธ๋ฅผ ํž™์œผ๋กœ ๋ณ€ํ™˜
peek (heap[0]) O(1) ์ตœ์†Œ๊ฐ’ ํ™•์ธ
nsmallest(k) O(N log k) ๊ฐ€์žฅ ์ž‘์€ k๊ฐœ
nlargest(k) O(N log k) ๊ฐ€์žฅ ํฐ k๊ฐœ

10.2 ํž™ ์ •๋ ฌ ์‹œ๊ฐ„๋ณต์žก๋„

# ํž™ ์ •๋ ฌ
def heap_sort(arr):
    heapq.heapify(arr)  # O(N)
    return [heapq.heappop(arr) for _ in range(len(arr))]  # O(N log N)

# ์ „์ฒด ์‹œ๊ฐ„๋ณต์žก๋„: O(N log N)
# ๊ณต๊ฐ„๋ณต์žก๋„: O(1) (in-place) ๋˜๋Š” O(N)

10.3 ์ •๋ ฌ vs ํž™ ๋น„๊ต

์ƒํ™ฉ ์ •๋ ฌ ํž™
์ „์ฒด ์ •๋ ฌ ํ•„์š” O(N log N) โœ“ O(N log N)
์ƒ์œ„ K๊ฐœ๋งŒ ํ•„์š” O(N log N) O(N log K) โœ“
๋™์  ์‚ฝ์ž…/์‚ญ์ œ O(N) O(log N) โœ“
์ตœ๋Œ€/์ตœ์†Œ 1๋ฒˆ๋งŒ O(N) โœ“ O(N)

์ฐธ๊ณ  ์ž๋ฃŒ

heapq ํ™œ์šฉ ํŒ

import heapq

# 1. ๊ธฐ์กด ๋ฆฌ์ŠคํŠธ๋ฅผ ํž™์œผ๋กœ (in-place)
nums = [5, 3, 8, 1]
heapq.heapify(nums)  # nums๊ฐ€ ์ง์ ‘ ๋ณ€๊ฒฝ๋จ

# 2. ์ƒ์œ„ K๊ฐœ (์ •๋ ฌ๋ณด๋‹ค ํšจ์œจ์ )
top_3 = heapq.nlargest(3, nums)  # O(N log 3)

# 3. ํŠœํ”Œ ํ™œ์šฉ (๋‹ค์ค‘ ๊ธฐ์ค€ ์ •๋ ฌ)
# (์šฐ์„ ์ˆœ์œ„1, ์šฐ์„ ์ˆœ์œ„2, ๊ฐ’)
heap = []
heapq.heappush(heap, (1, 'a', 'data1'))
heapq.heappush(heap, (1, 'b', 'data2'))

# 4. ์Œ์ˆ˜ ๋ณ€ํ™˜์œผ๋กœ ์ตœ๋Œ€ ํž™
heapq.heappush(heap, -value)
max_val = -heapq.heappop(heap)

์ฃผ์˜์‚ฌํ•ญ

import heapq

# ๋นˆ ํž™์—์„œ pop ์‹œ ์—๋Ÿฌ
heap = []
heapq.heappop(heap)  # IndexError

# ํ•ญ์ƒ ํ™•์ธ ํ›„ pop
if heap:
    heapq.heappop(heap)

# heapify๋Š” in-place (๋ฐ˜ํ™˜๊ฐ’ None)
nums = [5, 3, 8]
result = heapq.heapify(nums)  # result๋Š” None!
# nums๊ฐ€ ์ง์ ‘ ๋ณ€๊ฒฝ๋จ

ํž™ vs ๋‹ค๋ฅธ ์ž๋ฃŒ๊ตฌ์กฐ ์„ ํƒ

์ž๋ฃŒ๊ตฌ์กฐ ์ตœ์†Œ/์ตœ๋Œ€ ์ ‘๊ทผ ์‚ฝ์ž… ์‚ญ์ œ ํƒ์ƒ‰
์ •๋ ฌ ๋ฐฐ์—ด O(1) O(N) O(N) O(log N)
ํž™ O(1) O(log N) O(log N) O(N)
BST (๊ท ํ˜•) O(log N) O(log N) O(log N) O(log N)

ํž™ ์„ ํƒ ๊ธฐ์ค€:

  • ์ตœ๋Œ€/์ตœ์†Œ๋งŒ ์ž์ฃผ ํ•„์š” โ†’ ํž™ โœ“
  • ํŠน์ • ๊ฐ’ ํƒ์ƒ‰์ด ์ž์ฃผ ํ•„์š” โ†’ BST
  • ์ „์ฒด ์ •๋ ฌ ํ•„์š” โ†’ ์ •๋ ฌ ์•Œ๊ณ ๋ฆฌ์ฆ˜