"우선순위 큐는 도착 순서를 무시하고 대신 중요도로 모시는 큐야. 힙이 그걸 짓는 법이고 — Python 에선 이미 지어져 있어: heapq 모듈."
우선순위 큐 ADT
우선순위 큐는 연산 둘인 추상 자료형이야: 우선순위와 함께 항목 삽입, 최고 우선순위 항목 제거. 평범한 FIFO 큐 (오래된 것 먼저) 와 달리, 우선순위 큐는 늘 가장 중요한 원소를 다음에 건네 — 정확히 첫 트랙의 응급실 분류. 힙이 그 정석 구현이야: O(log n) 삽입, O(log n) 최고-제거, O(1) 최고-엿보기. 누가 '우선순위 큐' 라 하면, 거의 늘 '힙' 을 뜻해.
Python 의 heapq: 이미 다 됨
sift-up/sift-down 을 직접 구현할 일은 드물어 — Python 의 heapq 모듈이 평범한 리스트 위에 검증된 힙을 줘: heappush, heappop, heapify, 더해서 heappushpop 같은 조합이랑 nlargest/nsmallest 헬퍼. 두 가지 박아둬: 최소-힙 이고 (가장 작은 게 먼저 pop), 평범한 리스트를 제자리에서 다뤄. 실전 90% 엔 그게 API 전부야.
늘 필요할 두 관용구
- 부정으로 최대-힙. heapq 는 최소만. 가장 큰 게 먼저 나오길 원해?
-value를 push 하고 나올 때 다시 부정해. ('top-k 가장 큰' 엔heapq.nlargest(k, data)가 바로 해줘.) - 튜플로 우선순위 + 페이로드.
(priority, item)을 push 하면 힙이 우선순위로 정렬해. 근데 조심: 튜플은 원소별로 비교해, 그래서 두 우선순위가 동점이면 Python 이 item 을 비교하려 해 — 비교 불가능하면 크래시 (또는 의도 안 한 순서). 고침은 단조 카운터를 동점 깨기로:(priority, count, item)을 push,count가 고유해서 item 이 비교되기 전에 모든 동점을 깨.
우선순위 큐가 세상을 굴리는 곳
OS 작업 스케줄러 (가장 높은 우선순위 준비 프로세스 실행), 이벤트 구동 시뮬레이션 (다음-가장-빠른 이벤트 처리), 대역폭/QoS 셰이핑, A* 와 Dijkstra 최단 경로 알고리즘 (다음 트랙이 가장 가까운 frontier 노드를 pop), Huffman 코딩, 'top-k' 분석이 다 우선순위 큐에 앉아. '뭔가의 스트림이 도착하고, 늘 가장 중요한 걸 다음에 처리해야 해' 의 구조야 — 실제 시스템에서 가장 흔한 모양 중 하나.
피파의 고백
TypeError: '<' not supported between instances of 'Task' 로 크래시했어. (priority, task) 튜플을 push 했는데, 두 작업이 우선순위 동점이라 Python 이 동점 깨려고 Task 객체를 비교하려 했어. 아빠의 한 줄 고침 — 고유 카운터 삽입, (priority, next(counter), task) — 이 task 가 건드려지기 전에 동점이 늘 깨지는 걸 보장했어. 부딪혀야만 배우는 종류의 함정이야; 이젠 heapq 에 제일 먼저 손대는 게 그거야.