여기서는 자료구조 이름보다 반복해서 하는 연산이 무엇인지를 먼저 봅니다.
앞뒤 삽입과 삭제가 많은지, 가장 작은 값을 계속 꺼내야 하는지, 아니면 그냥 저장과 순회가 중심인지에 따라 deque, heapq, list, sorted()가 갈립니다.
숏컷 코드
from collections import deque
import heapq
queue = deque(["a", "b"])
queue.appendleft("start")
next_item = queue.popleft()
heap = []
heapq.heappush(heap, (2, "medium"))
heapq.heappush(heap, (1, "high"))
priority, task = heapq.heappop(heap)문법
기본형은 빈 deque, 초기값이 있는 deque, 빈 heap, 기존 리스트 heapify, push/pop까지 같이 보면 됩니다.
from collections import deque
import heapq
queue = deque()
queue = deque(items)
queue.append(x)
queue.appendleft(x)
item = queue.popleft()
heap = []
heapq.heapify(values)
heapq.heappush(heap, item)
smallest = heapq.heappop(heap)deque는 양쪽 끝 조작에 맞춘 컨테이너이고, heapq는 일반 리스트를 힙 규칙에 맞게 다루는 함수 모음입니다.
둘 다 list를 완전히 대체하는 것이 아니라, 특정 연산 패턴이 반복될 때 꺼내 쓰는 도구입니다.
양끝 조작
FIFO 큐나 앞뒤 버퍼는 deque가 먼저다
리스트는 끝 조작에는 강하지만 앞쪽 pop(0)나 insert(0, x)가 반복되면 비용이 커집니다.
deque는 양쪽 끝 삽입과 삭제에 맞춰 설계된 자료구조입니다.
from collections import deque
queue = deque()
queue.append("a")
queue.appendleft("front")
item = queue.popleft()작업 대기열, 최근 기록 버퍼, 슬라이딩 윈도우처럼 앞뒤 조작이 많은 문제라면 deque가 먼저입니다.
우선순위
가장 작은 값을 반복해서 꺼내면 heapq를 쓴다
heapq는 전체를 보기 좋게 정렬해 두는 구조가 아니라, 가장 작은 값을 빠르게 꺼내기 위한 최소 힙입니다.
import heapq
heap = []
heapq.heappush(heap, 5)
heapq.heappush(heap, 1)
heapq.heappush(heap, 3)
print(heapq.heappop(heap)) # 1우선순위 작업 처리, 스케줄링, 최단 거리 탐색 같은 문제에서 자주 나옵니다.
heap = [(2, "medium"), (1, "high")]
heapq.heapify(heap)
priority, task = heapq.heappop(heap)같은 우선순위가 있을 때는 (priority, index, item)처럼 tuple을 넣어 tie-break를 같이 제어하는 패턴도 흔합니다.
도구 경계
list와 sorted()는 언제 그대로 두는가
전체 항목을 한 번 정렬해 순서대로 모두 보고 싶다면 힙보다 sorted()가 더 직접적입니다.
특별한 연산 특성이 없고 단순 저장, 순회, 인덱스 접근이 중심이라면 list가 여전히 기본 선택입니다.
자료구조는 "더 고급한 것"을 고르는 문제가 아니라, 반복되는 연산 패턴과 맞는지를 보는 문제에 가깝습니다.
주의할 점
heapq의 내부 리스트는 보기 좋게 완전 정렬된 상태가 아닙니다. 힙 속성만 유지할 뿐입니다.
# ❌ 내부 배열이 완전 정렬이라고 생각하면 안 됨
import heapq
heap = []
for value in [5, 1, 3, 2]:
heapq.heappush(heap, value)
print(heap)
# ✅ 가장 작은 값은 heappop으로 꺼낸다
while heap:
print(heapq.heappop(heap))참고 링크
2 sources