heapq 모듈

2025-07-21


Python의 heapq 모듈

Python의 heapq 모듈은 힙(Heap) 자료구조를 구현하는 모듈로, 우선순위 큐(Priority Queue)를 효율적으로 구현할 수 있게 해줍니다.


heapq 모듈 특징

  • 최소 힙(Min Heap): 가장 작은 값이 루트에 위치
  • 이진 힙(Binary Heap): 완전 이진 트리 구조 (트리 자료 구조)
  • O(log n): 삽입, 삭제 시간복잡도
  • O(1): 최솟값 조회 시간복잡도
  • 리스트 기반: Python 리스트를 힙으로 변환하여 사용

import 방법

import heapq
 
# 또는
from heapq import heappush, heappop, heapify, heappushpop, heapreplace

heapq 주요 함수

주요 함수 정리

함수설명시간복잡도
heapify(heap)리스트를 힙으로 변환 (in-place)O(n)
heappush(heap, item)힙에 요소 추가O(log n)
heappop(heap)힙에서 최솟값 제거하고 반환O(log n)
heappushpop(heap, item)힙에 item 추가 후 최솟값 반환 (heappush + heappop)O(log n)
heapreplace(heap, item)힙에서 최솟값 제거 후 item 추가 (heappop + heappush)O(log n)
nlargest(n, iterable, key=None)iterable에서 가장 큰 n개 요소 반환O(n log k)
nsmallest(n, iterable, key=None)iterable에서 가장 작은 n개 요소 반환O(n log k)

기본 사용법

import heapq
 
# 빈 힙 생성
heap = []
 
# 요소 추가
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))  # 1
print(heap)  # [3, 4, 7]
 
# 기존 리스트를 힙으로 변환
numbers = [5, 2, 8, 1, 9]
heapq.heapify(numbers)
print(numbers)  # [1, 2, 8, 5, 9] (힙 구조)

heappush와 heappop

import heapq
 
heap = []
 
# heappush: 요소 추가
heapq.heappush(heap, 10)
heapq.heappush(heap, 5)
heapq.heappush(heap, 15)
heapq.heappush(heap, 3)
print(heap)  # [3, 5, 15, 10]
 
# heappop: 최솟값 제거 및 반환
print(heapq.heappop(heap))  # 3
print(heap)  # [5, 10, 15]
 
print(heapq.heappop(heap))  # 5
print(heap)  # [10, 15]

heapify

import heapq
 
# 기존 리스트를 힙으로 변환
numbers = [9, 2, 7, 1, 5, 8, 3]
heapq.heapify(numbers)
print(numbers)  # [1, 2, 3, 9, 5, 8, 7]
 
# 힙 구조 확인
print(heapq.heappop(numbers))  # 1
print(heapq.heappop(numbers))  # 2
print(heapq.heappop(numbers))  # 3

heappushpop과 heapreplace

import heapq
 
heap = [3, 5, 7, 9]
 
# heappushpop: 추가 후 최솟값 반환
result = heapq.heappushpop(heap, 2)
print(result)  # 2 (추가된 값이 최솟값이었음)
print(heap)    # [3, 5, 7, 9]
 
result = heapq.heappushpop(heap, 10)
print(result)  # 3 (기존 최솟값 반환)
print(heap)    # [5, 9, 7, 10]
 
# heapreplace: 최솟값 제거 후 추가
result = heapq.heapreplace(heap, 1)
print(result)  # 5 (제거된 최솟값)
print(heap)    # [1, 9, 7, 10]

nlargest와 nsmallest

import heapq
 
numbers = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5]
 
# 가장 큰 3개 요소
largest = heapq.nlargest(3, numbers)
print(largest)  # [9, 6, 5]
 
# 가장 작은 3개 요소
smallest = heapq.nsmallest(3, numbers)
print(smallest)  # [1, 1, 2]
 
# key 함수 사용 (문자열 길이 기준)
words = ['apple', 'banana', 'cherry', 'date', 'elderberry']
longest = heapq.nlargest(2, words, key=len)
print(longest)  # ['elderberry', 'banana']

우선순위 큐 구현

튜플을 이용한 우선순위 큐

import heapq
 
# (우선순위, 데이터) 형태로 저장
pq = []
heapq.heappush(pq, (3, 'task3'))
heapq.heappush(pq, (1, 'task1'))
heapq.heappush(pq, (2, 'task2'))
 
# 우선순위가 낮은 순서대로 처리
while pq:
    priority, task = heapq.heappop(pq)
    print(f"Processing {task} with priority {priority}")
 
# 출력:
# Processing task1 with priority 1
# Processing task2 with priority 2
# Processing task3 with priority 3

최대 힙 구현

import heapq
 
# 최대 힙: 음수로 변환하여 저장
max_heap = []
numbers = [3, 1, 4, 1, 5, 9, 2, 6]
 
# 음수로 변환하여 최소 힙에 저장
for num in numbers:
    heapq.heappush(max_heap, -num)
 
# 최댓값 추출 (음수로 저장했으므로 다시 양수로 변환)
print(-heapq.heappop(max_heap))  # 9
print(-heapq.heappop(max_heap))  # 6
print(-heapq.heappop(max_heap))  # 5

실전 활용 예시

Top K 문제

import heapq
 
def find_top_k(nums, k):
    """가장 큰 k개 요소 찾기"""
    return heapq.nlargest(k, nums)
 
def find_bottom_k(nums, k):
    """가장 작은 k개 요소 찾기"""
    return heapq.nsmallest(k, nums)
 
# 예시
numbers = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5]
print(find_top_k(numbers, 3))    # [9, 6, 5]
print(find_bottom_k(numbers, 3)) # [1, 1, 2]

heapq 실전 활용 팁 및 주의사항

주요 팁

  • 최소 힙만 지원: 최대 힙이 필요하면 음수로 변환하여 사용
  • 리스트 기반: 기존 리스트를 heapify()로 힙으로 변환 가능
  • 안정성: 같은 우선순위의 요소들은 삽입 순서대로 처리되지 않을 수 있음
  • 메모리 효율성: 리스트를 직접 힙으로 사용하므로 메모리 효율적
  • 정렬과의 차이: 전체 정렬이 아닌 최솟값만 빠르게 접근

주의사항

  • 힙 구조 유지: heappush, heappop 외의 방법으로 리스트 수정 시 힙 구조가 깨질 수 있음
  • 중복 요소: 같은 값이 여러 개 있을 수 있음
  • 정렬되지 않음: 힙은 완전히 정렬된 상태가 아님 (부모-자식 관계만 보장)
  • 인덱스 접근: heap[0]으로 최솟값만 안전하게 접근 가능

성능 비교

연산heapq정렬된 리스트일반 리스트
최솟값 접근O(1)O(1)O(n)
삽입O(log n)O(n)O(1)
삭제O(log n)O(n)O(n)
전체 정렬O(n log n)O(n log n)O(n log n)

언제 사용할까?

  • 우선순위 큐: 작업 스케줄링, 이벤트 처리
  • Top K 문제: 가장 큰/작은 k개 요소 찾기
  • 중간값 찾기: 실시간 데이터 스트림에서 중간값 계산
  • 최단 경로: 다익스트라, 프림 알고리즘
  • 힙 정렬: O(n log n) 정렬 알고리즘 구현

댓글

GitHub 계정으로 댓글을 남겨보세요!