[Python ์ž๋ฃŒ๊ตฌ์กฐ] Heap (ํž™)

2021. 1. 9. 00:07ใ†๐Ÿ“š Algorithm/๐Ÿ“• Python ๋ฌธ๋ฒ•

๋ฐ˜์‘ํ˜•

 

ํŒŒ์ด์ฌ์—์„œ์˜ Heap ?!

Python์—์„œ์˜ Heap์€ heapq ๋ชจ๋“ˆ๊ณผ Queue ๋ชจ๋“ˆ์˜ PriorityQueue ํด๋ž˜์Šค๋ฅผ ํ†ตํ•ด heapq๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

๋‹จ, MinHeap์œผ๋กœ ๊ตฌํ˜„๋˜์–ด์žˆ์–ด ๊ฐ€์žฅ ์•ž์— ์žˆ๋Š” ์›์†Œ๊ฐ€ ๊ฐ€์žฅ ์ž‘์€ ์›์†Œ๊ฐ€ ๋ฉ๋‹ˆ๋‹ค.

 

heapq ์™€ PriorityQueue ์˜ ๊ณตํ†ต์ ๊ณผ ์ฐจ์ด์ 

๊ณตํ†ต์ ์€ ๋‘˜๋‹ค MinHeap์œผ๋กœ ๊ตฌํ˜„๋˜์–ด ์žˆ๋‹ค๋Š” ์ ์ž…๋‹ˆ๋‹ค. ์ฆ‰ ๊ฐ€์žฅ ์•ž์— ์žˆ๋Š” ์›์†Œ๊ฐ€ ๊ฐ€์žฅ ์ž‘์€ ์›์†Œ ์ž…๋‹ˆ๋‹ค.

์ฐจ์ด์ ์€ PriorityQueue๋Š” ํด๋ž˜์Šค์ด๊ณ , heapq๋Š” ๋ชจ๋“ˆ์ด๋ผ๋Š” ์ ์ž…๋‹ˆ๋‹ค.

 

ํž™์— ๋ฐ์ดํ„ฐ๋ฅผ ๋„ฃ์œผ๋ ค๋ฉด !?
PriorityQueue๋Š” ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑ ํ›„ ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•ด์•ผํ•œ๋‹ค.
heapq๋Š” ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜์ง€ ์•Š๊ณ  heapify(๋ฆฌ์ŠคํŠธ ๊ฐ์ฒด)์ฒ˜๋Ÿผ ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ์‚ฌ์šฉํ•œ๋‹ค.

 

Heap์„ ์–ธ์ œ ์‚ฌ์šฉํ•˜๋ฉด ์ข‹์„๊นŒ?!

1. ๋ฐ์ดํ„ฐ๊ฐ€ ์ง€์†์ ์œผ๋กœ ์ •๋ ฌ์ด ๋˜์–ด์•ผ ํ•  ๋•Œ

2. ๋ฐ์ดํ„ฐ์˜ ์‚ฝ์ž… / ์‚ญ์ œ๊ฐ€ ๋นˆ๋ฒˆํžˆ ์ผ์–ด๋‚  ๋•Œ

 

Heap์˜ ์‹œ๊ฐ„ ๋ณต์žก๋„

Operation Time Complexity - Worst Case
Get Item O(1)
Insert Item O(logn)
Delete Item O(logn)
Search Item O(n)

 

heapq - heapify

heapq ๋ชจ๋“ˆ์˜ heapify ํ•จ์ˆ˜๋Š” ์ฃผ์–ด์ง„ ๋ฆฌ์ŠคํŠธ๋ฅผ ํž™ ์ •๋ ฌํ•  ๋•Œ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ์ด๋•Œ์˜ Time Complexity๋Š” O(nlogn)์ž…๋‹ˆ๋‹ค.

import heapq

my_list = [3, 2, 1, 5, 7]
heapq.heapify(my_list) #[1,2,3,5,7]

 

heapq - heappop(heap)

heapq ๋ชจ๋“ˆ์—์„œ์˜ heappop ํ•จ์ˆ˜๋Š” ํž™ ์ •๋ ฌ๋œ ๋ฆฌ์ŠคํŠธ์—์„œ ์•„๋ž˜์™€ ๊ฐ™์€ ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค.

1. ๊ฐ€์žฅ ์ž‘์€ ์›์†Œ๋ฅผ ๋นผ๋‚ธ๋‹ค.

2. ๋‚˜๋จธ์ง€ ์›์†Œ๊ฐ€ ํž™์„ ์œ ์ง€ํ•˜๋„๋ก ์ •๋ ฌํ•œ๋‹ค.

 

โœ”๏ธ๋ฆฌ์ŠคํŠธ๊ฐ€ ํž™ ์ •๋ ฌ๋˜์–ด ์žˆ์ง€ ์•Š์€ ์ƒํƒœ์—์„œ heappop ์‚ฌ์šฉ ์‹œ, ์ด์ƒํ•œ ๊ฒฐ๊ณผ๊ฐ€ ๋‚˜์˜ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค!!

import heapq
my_list = [13, 2, 1, 5, 10]
heapq.heapify(my_list)

# ๊ฐ€์žฅ ์ž‘์€ ์›์†Œ์ธ 1์ด ๋ฆฌํ„ด๋ฉ๋‹ˆ๋‹ค. my_list์˜ ๊ธธ์ด๊ฐ€ ํ•˜๋‚˜ ์ค„์–ด๋“ญ๋‹ˆ๋‹ค.
ret_val = heapq.heappop(my_list)

print("๋ฆฌํ„ด๋œ ๊ฐ’:", ret_val) # 1
print("๋‚จ์€ ์›์†Œ:", my_list) # [2,5,13,10]

 

heapq - heappush(heap, item)

heapq ๋ชจ๋“ˆ์—์„œ์˜ heappush ํ•จ์ˆ˜๋Š” ๋ฆฌ์ŠคํŠธ์˜ ํž™ ์ƒํƒœ๋ฅผ ์œ ์ง€ํ•˜๋ฉฐ, ๋ฐ์ดํ„ฐ๋ฅผ ์‚ฝ์ž…์‹œ์ผœ ์ค๋‹ˆ๋‹ค.

โœ”๏ธ๋ฆฌ์ŠคํŠธ๊ฐ€ ํž™ ์ •๋ ฌ๋˜์–ด ์žˆ์ง€ ์•Š์€ ์ƒํƒœ์—์„œ heappush ์‚ฌ์šฉ ์‹œ, ์ด์ƒํ•œ ๊ฒฐ๊ณผ๊ฐ€ ๋‚˜์˜ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค!!

import heapq
my_list = [13, 2, 1, 5, 10]
heapq.heapify(my_list)

# 7 ์‚ฝ์ž…
heapq.heappush(my_list, 7)

# ๊ธฐ์กด์— ๊ฐ€์žฅ ์ž‘์•˜๋˜ ์›์†Œ๊ฐ€ ๊ณ„์† ์•ž์— ์œ„์น˜
print("๋‚จ์€ ์›์†Œ:", my_list)
# ๋‚จ์€ ์›์†Œ: [1, 2, 7, 5, 10, 13]

 

heapq - ๊ฐ€์žฅ ์ž‘์€ ์›์†Œ์— ์ ‘๊ทผํ•˜๋Š” ๋ฐฉ๋ฒ•

heap ๋ฆฌ์ŠคํŠธ์—์„œ ๊ฐ€์žฅ ์ž‘์€ ์›์†Œ๋ฅผ ์‚ญ์ œํ•˜์ง€ ์•Š๊ณ  ๋‹จ์ˆœํžˆ ์ฝ๊ธฐ๋งŒ ์‚ฌ์šฉํ•  ๋•Œ ๋ฆฌ์ŠคํŠธ์™€ ๊ฐ™์ด ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

import heapq
my_list = [13, 2, 1, 5, 10]
heapq.heapify(my_list)

# heappop์„ ํ•˜์ง€๋งŒ, ๋งจ ์•ž ์›์†Œ๊ฐ€ ์ตœ์†Ÿ๊ฐ’์ž„์€ ๋ณ€ํ•˜์ง€ ์•Š์Œ
while my_list:
    print("๋ฆฌ์ŠคํŠธ์˜ ๋งจ ์•ž ์›์†Œ:", my_list[0])
    heapq.heappop(my_list)

'''
๋ฆฌ์ŠคํŠธ์˜ ๋งจ ์•ž ์›์†Œ: 1
๋ฆฌ์ŠคํŠธ์˜ ๋งจ ์•ž ์›์†Œ: 2
๋ฆฌ์ŠคํŠธ์˜ ๋งจ ์•ž ์›์†Œ: 5
๋ฆฌ์ŠคํŠธ์˜ ๋งจ ์•ž ์›์†Œ: 10
๋ฆฌ์ŠคํŠธ์˜ ๋งจ ์•ž ์›์†Œ: 13
'''

 

+) heapq - ์ตœ๋Œ€ ํž™ (Max Heap) ๊ตฌํ˜„ํ•˜๊ธฐ

heapq๋Š” ์ตœ์†Œ ํž™์ด๋ผ๋Š” ๊ฒƒ์„ ์ด์šฉํ•˜์—ฌ ๋ชจ๋“  ๊ฐ’์— -๋ฅผ ๋ถ™์—ฌ - ์ตœ๋Œ€ ๊ฐ’์ด ์ตœ์†Œ ๊ฐ’์ด ๋˜๋„๋ก ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

import heapq

nums = [5,1,10,13,2]
heap = []

for num in nums:
  heapq.heappush(heap, (-num, num))  # (์šฐ์„  ์ˆœ์œ„, ๊ฐ’)

while heap:
  print("๋ฆฌ์ŠคํŠธ์˜ ๋งจ ์•ž ์›์†Œ :", heapq.heappop(heap)[1])  # index 1
  
'''
๋ฆฌ์ŠคํŠธ์˜ ๋งจ ์•ž ์›์†Œ: 13
๋ฆฌ์ŠคํŠธ์˜ ๋งจ ์•ž ์›์†Œ: 10
๋ฆฌ์ŠคํŠธ์˜ ๋งจ ์•ž ์›์†Œ: 5
๋ฆฌ์ŠคํŠธ์˜ ๋งจ ์•ž ์›์†Œ: 2
๋ฆฌ์ŠคํŠธ์˜ ๋งจ ์•ž ์›์†Œ: 1
'''

 

+) K๋ฒˆ์งธ ์ตœ์†Œ๊ฐ’ / ์ตœ๋Œ“๊ฐ’ ๊ตฌํ•˜๊ธฐ

Heap์„ ์‚ฌ์šฉํ•˜์—ฌ K ๋ฒˆ์งธ์˜ ์ตœ์†Œ๊ฐ’, ์ตœ๋Œ€๊ฐ’์„ ํšจ์œจ์ ์œผ๋กœ ๊ตฌํ•˜์‹ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

import heapq

def kth_smallest(nums, k):
  heap = []
  for num in nums:
    heapq.heappush(heap, num)

  kth_min = None
  for _ in range(k):
    kth_min = heapq.heappop(heap)
  return kth_min

print(kth_smallest([4, 1, 7, 3, 8, 5], 3)) # 4
๋ฐ˜์‘ํ˜•