본문 바로가기
ALGORITHMS/THEORY

[PYTHON] PriorityQueue, heapq

by alasdkfm 2023. 5. 25.

목차

    우선순위 큐?

    • GREEDY알고리즘 문제는 정렬 아니면 우선순위 큐 문제일 정도로 자주 쓰이는 자료구조.
    • 일반적인 QUEUE처럼, 데이터가 들어온 순서대로 나가는 것이 아니라, 우선순위가 높은 데이터가 먼저 출력되는 자료구조.
    • 우선순위 큐는 힙으로 구현 가능한데, 최소값 우선큐 = 최소힙 & 최대값 우선큐 = 최대힙
    • O(logn) 의 시간복잡도
    • PriorityQueue 와 heapq 모두 최소힙( 작은값부터 출력) 만 지원.

    queue.PriorityQueue( )

    Tip

    queue 모듈의 다음과 같은 클래스들 에서, 동일 메소드 사용 가능.

    queue.Queue ( maxSize )  기본 큐. FIFO 구조
    queue.SimpleQueue 입력 제한 없는 FIFO 큐
    queue.LifoQueue (maxSize) 스택. LIFO
    queue.PriorityQueue(maxSize) 우선순위 큐. 웃자가 작을수록 높은순위 가짐

     

    활용

    선언

    from queue import PriorityQueue queue = PriorityQueue() # 큐의 크기 제한 가능 max_queue = PriorityQueue( maxsize = 5 )

     

    삽입 : put( ) , put_nowait( )

    queue.put(1) queue.put(5) # put( 우선순위, 값 ) queue.put(3,"hello") queue .put_nowait(2) #큐가 가득 차면 queue.Full 예외 발생

    put_nowait( ) 이 필요한 이유: put( )을 사용하면 queue가 가득 찼을 경우, 빈자리가 생길 때 까지 무한 대기하다 빈자리 생기면 등록함.

    따라서 크기 제한이 있는 queue의 경우, put_nowait( )을 사용

     

    우선순위 큰 값부터 반환

    # 선언시 튜플 형태로 값을 삽입함 ( - 값 , 값 ) numbers = [2,5,4,1,3,6] for num in numbers: ‌queue.put(-num,num)

     

    삭제 (반환 O, 삭제 O ) : get( ) , get_nowait( ) — 작은 값 먼저 반환

    queue.get() queue.get()[1] #튜플에서 값 반환 queue.get_nowait() #큐가 비었을 우 queue.Empty 예외 발생

    get_nowait( ) 이 필요한 이유: 큐에 값이 없을 경우, 무한대기함

     

    크기 : qsize( )

    queue .qsize()

     

    비었는지/ 가득 찼는지 확인 : empty( ) , full( ) - T/F 반환

    queue.empty() # 비었는지 확인 queue.full() # 찼는지 확인 - maxsize와 원소개수 비교

     

    heapq( ) - 파이썬에서 PriorityQueue() 보다 속도 ↑

    삽입/ 삭제 : heappush( ) , heappop( )

    import heapq queue = [] # 삽입 heapq. heappush( queue , 10 ) heapq. heappush( queue , 8 ) heapq. heappush( queue , 9 ) print(queue) #[8,9,10] # 삭제 heapq. heappop(queue) #8 heapq. heappop(queue) #9 heapq. heappop(queue) #10

     

    최소값 구하기 queue[0]

    queue[0] #인덱스 통해 접근 # !주의점! # 힙을 사용하여 만들어 졌기 때문에 0번째 요소가 가장 작다고 1번째 요소가 두번째 최소값이란 보장x # 왜냐면 원소 삭제시마다 매번 최소값을 0번 인덱스에 재배치 하기 떄문. # 그럼 2번째 최소값을 얻으려면? # queue.heappop() -> queue[0] 으로 접근해야함

     

    기존 리스트 힙으로 변환 heapify()

    시간 복잡도 : O(n)

    queue = [3,2,4,6,1,5] heapify(queue) print(queue) #[1,2,3,4,5,6]

     

    [응용] 최대힙 생성 : heappush( [리스트명] , ( - num , num ) )

    from heapq import heappush, heappop nums = [4, 1, 7, 3, 8, 5] heap = [] for num in nums: ​​heappush(heap, (-num, num)) # (우선 순위, 값) # 출력 while heap: ​​print(heappop(heap)[1]) # index 1

     

    [응용] n번째 최소/최대값 구하기 : nsmallest(개수,리스트) , nlargest(개수,리스트)

    총 n개의 최소값이 반환되기 때문에, 마지막 값이 구하고자 했던 값이다.

    from heapq import nsmallest nums = [4, 1, 7, 3, 8, 5] nsmallest(3, nums )[-1] # [1,3,5][-1] => 5 반환 nlargest(3, nums )[-1] # [8,7,5][-1] => 5 반환

     

    nsmallest 구현

    python
    닫기
    from heapq import heapify, heappop def nsmallest(n,nums): ​​​​heapify(nums) ‌‌return [ heappop(nums) for _ in range(n) ]

     

    nlargest 구현

    python
    닫기
    from heapq import heapify, heappop def nlargest (n,nums): ​​​​heap = [] ​​​​for num in nums: ​​​​​​​​heappush(heap, (-num, num) ) ​​​​return [heappop(heap)[1] for _ in range(n)]

     

    [응용] 힙정렬

    from heapq import heappush, heappop def heap_sort(nums): ​​heap = [] ​​for num in nums: ​​​​heappush(heap, num) ​​sorted_nums = [] ​​while heap: ​​​​sorted_nums.append(heappop(heap)) ​​return sorted_nums print(heap_sort([4, 1, 7, 3, 8, 5])) # [1,3,4,5,7,8]

     

     

     

    참고 :

    파이썬의 heapq 모듈로 힙 자료구조 사용하기 | Engineering Blog by Dale Seo

    [Python] 우선순위 큐(PriorityQueue) 사용 방법 - 지니의 기록 (tistory.com)

    [Python:자료구조] 파이썬 큐(Queue) , 우선순위 큐(PriorityQueue) 사용방법 및 예제 총정리 - 정보의 공유 사회 (tistory.com)

    'ALGORITHMS > THEORY' 카테고리의 다른 글

    [JAVA] PriorityQueue : 우선순위 큐  (0) 2023.05.25
    약수 효율적으로 찾기  (0) 2022.11.23