자료구조 힙을 사용하기 위해서 heapq의 사용법과 관련 함수들에 대해 공부해보자.
from heapq import *
or
import heapq
heap = [] // heapq를 사용해 최소 힙으로 다룰 리스트
heapq.heappush(heap,4)
heapq.heappush(heap,1)
heapq.heappush(heap,7)
heapq.heappush(heap,3)
print(heap)
==>
[1,3,7,4]
print(heapq.heappop(heap))
print(heap)
==>
1
[3,4,7]
print(heapq.heappop(heap))
print(heap)
==>
3
[4,7]
힙에서 최소값을 삭제하지 않고 단순히 읽기만 하려면 일반적으로 리스트의 첫번째 원소에 접근하듯이 인덱스를 통해 접근하면 된다.
print(heap[0])
==>
4
여기서 주의사항은 인덱스 0에 가장 작은 원소가 있다고 해서, 인덱스 1에 두번째 작은 원소, 인덱스 2에 세번째 작은 원소가 있다는 보장은 없다는 것이다.
왜냐하면 힙은 heappop() 함수를 호출하여 원소를 삭제할 때마다 이진 트리의 재배치를 통해 매번 새로운 최소값을 인덱스 0에 위치시키기 때문이다.
따라서 두번째로 작은 원소를 얻으려면 바로 heap[1]으로 접근하면 안되고, 반드시 heappop()을 통해 가장 작은 원소를 삭제 후에 heap[0]를 통해 새로운 최소값에 접근해야 한다.
이미 원소가 들어있는 리스트를 힙으로 만드려면 heapq 모듈의 heapify() 함수를 이용하면 된다.
heap = [4,1,7,3,8,5]
heapq.heapify(heap)
print(heap)
==>
[1,3,5,4,8,7]
import heapq
nums = [4, 1, 7, 3, 8, 5]
heap = []
for num in nums:
heapq.heappush(heap, (-num, num)) # (우선 순위, 값)
while heap:
print(heapq.heappop(heap)[1]) # index 1
==>
8
7
5
4
3
1
최소 힙이나 최대 힙을 사용하면 K번째 최소값이나 최대값을 효율적으로 구할 수 있다.
import heapq
# min heap
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_smalles([4,1,7,3,8,5],3))
==>
4
# max heap
def kth_biggest(nums,k):
heap = []
for num in nums:
heapq.heappush(heap, -(num,num))
kth_max = None
for _ in range(k):
kth_max = heapq.heappop(heap)[1]
return kth_max
print(kth_biggest([4,1,7,3,8,5],3))
==>
5
K번째 최소값을 구하기 위해서는 주어진 배열로 힙을 만든 후, heappop() 함수를 K번 호출하면 된다.
힙 정렬(heap sort)은 힙 자료구조의 성질을 이용한 대표적인 정렬 알고리즘이다.
import heapq
def heap_sort(nums):
heap = []
for num in nums:
heapq.heappush(heap,num)
sorted_nums =[]
while heap:
sorted_nums.append(heapq.heappop(heap))
return sorted_nums
print(heap_sort([4,1,7,3,8,5]))
==>
[1,3,4,5,7,8]
# heapq 함수 정리
import heapq
heap = []
# 삽입
heapq.heappush(heap, value)
# 삭제
heapq.heappop(heap)
# peek
heap[0]
# 리스트를 heap으로 변환
heapq.heapify(heap)