힙(heap)은 부분적으로 정렬되어 있는 완전 이진 트리(complete binary tree) 자료구조로, 우선순위 큐를 구현할 때 사용이 됩니다.
여러 개의 값들 중 최솟값 혹은, 최댓값을 빠르게 구할 수 있는 것이 특징입니다.
가장 밑단 level을 제외하고는 완전히 채워져 있는 트리를 말합니다. 가장 밑단 level의 경우, 왼쪽에서 오른쪽의 순서로 노드들이 채워져 있습니다.
부모 노드의 값 자식 노드의 값인 힙을 말합니다.
자식 노드의 값 부모 노드의 값인 힙을 말합니다.
📌최소 힙을 기준으로 설명합니다.
📌최소 힙을 기준으로 설명합니다.
- 완전 이진 트리는 리스트로 구현할 수 있습니다.
- 인덱스가
N
인 노드의 경우
👉 부모의 인덱스는N // 2
👉 자식의 인덱스는N * 2
와N * 2 + 1
- 인덱스는
0
이 아닌1
부터 시작합니다.
0
부터 시작할 경우, 자식 노드의 인덱스를 구하는 데에 문제가 발생하기 때문입니다!
def insert(num):
index = len(q) # 새로 추가하는 가장 마지막 노드의 인덱스
q.append(num) # 마지막 노드에 insert
while index > 0: # 루트 노드까지만 진행
parent = index // 2 # 부모 노드의 인덱스
if q[parent] <= num: break
q[index], q[parent] = q[parent], num # 부모 노드의 값이 더 크다면 swap
index = parent
def delete():
q[-1], q[1] = q[1], q[-1] # 삭제할 루트 노드와 마지막 노드 swap
index = 1 # 루트 노드부터 시작
while index * 2 < len(q) - 1: # 자식 노드가 존재할 때까지만 반복
child = index * 2 # 왼쪽 자식 노드의 인덱스
# 오른쪽 자식이 존재하고, 왼쪽 > 오른쪽이라면 오른쪽 자식과 swap
if child + 1 < len(q) - 1 and q[child] > q[child + 1]: child += 1
if q[index] > q[child]: q[index], q[child] = q[child], q[index]
else: break
index = child
return q.pop()
최솟값, 혹은 최댓값을 구하기 위해서 순차 탐색을 하면, 의 시간이 걸립니다.
하지만, 힙을 사용하면 트리의 높이만큼만 비교하면 되기 때문에 시간복잡도를 줄일 수 있습니다.