세리프 따라잡기
WEEK02 - TIL 우선순위 큐(Priority Queue) 본문
- 우선순위 큐는 우선순위가 가장 높은 데이터를 가장 먼저 삭제하는 자료구조이다.
- 우선순위 큐는 데이터를 우선순위에 따라 처리하고 싶을 때 사용
ex. 어떤 물건 데이터를 자료구조에 넣었다가 가치가 높을 물건부터 꺼내서 확인해야 하는 경우, 우선순위 큐에 각각의 물건 정보를 가치 데이터와 함께 우선순위 큐에 넣었다가 꺼낼 때
자료구조 | 추출되는 데이터 |
스택 (stack) | 가장 나중에 삽입된 데이터 |
큐 (queue) | 가장 먼저 삽입된 데이터 |
우선순위 큐 (priority queue) | 가장 우선순위가 높은 데이터 |
- 우선순위 큐를 구현하는 방법
1. 단순히 리스트를 이용해 구현
= 리스트에 차례대로 데이터를 연달아 넣고, 꺼낼 때는 리스트에서 각각의 데이터를 확인한 다음에 값이 가장 큰 데이터를 뽑아 추출
2. 힙(heap)을 이용해 구현 (아래 자세히 설명~)
- 데이터의 개수가 n일때, 구현 방식(리스트, 힙)에 따라 시간 복잡도는 다음 표와 같다.
우선순위 큐 구현 방식 | 삽입 시간 | 삭제 시간 |
리스트 | O(1) | O(N) |
힙(Heap) | O(logN) | O(logN) |
리스트: 데이터를 삽입할 때 뒤에 연달아 넣으면 되기에 시간 복잡도는 1, 데이터를 삭제할 때는 우선순위가 가장 높은 데이터여야 하기 때문에 가장 높은 우선순위를 가지는 데이터를 찾기 위해 선형적인 탐색 시간을 갖게 된다.
힙: 데이터를 넣는 것과 빼는 과정에서 모두 최악의 경우에도 시간 복잡도 O(logN)을 보장하는 방식으로 동작
└→ 단순히 n개의 데이터를 힙에 넣었다가 모두 꺼내는 작업은 정렬과 동일하다 (힙 정렬) = 이 경우 시간 복잡도는 O(NlogN)이다. [병합 정렬과 같은 다른 일반적으로 사용되는 정렬 알고리즘과 동일하게 빠른 정렬 알고리즘 == 힙 정렬]
힙(heap)의 특징
- 힙은 완전 이진 트리 자료구조의 일종이다.
- 힙에서는 항상 루트 노드(root node)를 제거한다.
- 힙은 두 가지로 분리할 수 있다.
-- 최소 힙 (min heap)
- 루트 노드가 가장 작은 값을 가짐
- 따라서 값이 작은 데이터가 우선적으로 제거
☞ 오름차순 정렬을 한다고 하면 최소힙에 n개의 데이터를 넣고 꺼내기만 해도 오름차순 정렬된 데이터가 나옴
-- 최대 힙 (max heap)
- 루트 노드가 가장 큰 값을 가짐
- 따라서 값이 큰 데이터가 우선적으로 제거
* 완전 이진 트리 (Complete Binary Tree)
- 힙은 완전 이진 트리 형식을 따른다.
- 루트 노드부터 시작하여 왼쪽 자식 노드, 오른쪽 자식 노드 순서대로 데이터가 차례대로 삽입되는 트리를 의미
- 최소 힙 구성 함수: Min-Heapify()
= (상향식) 부모 노드로 거슬러 올라가며, 부모보다 자신의 값이 더 작은 경우에 위치를 교체
+ 힙에 새로운 원소가 삽입 = O(logN)의 시간 복잡도로 힙 성질을 유지하도록 한다.
이때 기본적으로 힙 자료구조는 완전 이진 트리를 따르기 때문에 균형 잡힌 트리로서 동작한다는 게 특징 == 즉, 최악의 경우에도 시간복잡도를 유지한다
+ 힙에서 원소가 제거될 때 = O(logN)의 시간 복잡도로 힙 설질을 유지하도록 한다.
원소를 제거할 때는 가장 마지막 노드가 루트 노드의 위치에 오도록 한다.
이후에 루트 노드에서부터 하향식으로(더 작은 자식 노드로) Heapify()를 진행한다.
- 우선순위 큐 라이브러리를 활용한 힙 정렬 구현 예제
import heapq #파이썬에서는 기본적으로 최소힙 형태로 동작해서 오름차순 정렬이 수행됨
import sys
input=sys.stdin.readline
def heapsort(iterable):
h = []
result = []
# 모든 원소를 차례대로 힙에 삽입
for value in iterable:
heapq.heappush(h,value) #담기 /// 최대힙으로 동작하게 만들고 싶으면 -를 붙여야 함!!
# heapq.heappush(h,-value) // 최대힙 예시
# 힙에 삽입된 모든 원소를 차례대로 꺼내어 담기
for i in range(len(h)):
result.append(heapq.heappop(h)) # 최대힙으로 동작하게 만들고 싶으면 -를 붙여야 함!!
# result.append(-heapq.heappop(h))
return result
n=int(input())
arr=[]
for i in range(n):
arr.append(int(input()))
res=heapsort(arr)
for i in range(n):
print(res[i])
heapq.heappush |
값을 heap으로 push |
heapq.heappop |
heap에서 가장 작은 항목을 pop하고 반환 *힙이 비어있으면 indexError가 발생하는데, 팝하지 않고 가장 작은 항목을 찾으려면 heap[0]이용 |
heapq.heappushpop |
값을 heap으로 push하고, heap에서 가장 작은 항목을 pop하고 반환하는 액션을 모두 한다. >> 별도로 호출하는 것보다 효율적으로 실행! |
이론 끗~💃
'SW사관학교 정글' 카테고리의 다른 글
WEEK03- TIL 최소 스패닝 트리 (0) | 2022.04.15 |
---|---|
WEEK02 - TIL 시간 복잡도(basic) (0) | 2022.04.12 |
WEEK02 - TIL 스택/큐 (0) | 2022.04.10 |
WEEK02- TIL 분할정복 (0) | 2022.04.09 |
WEEK02 - TIL 이분 탐색(이진 탐색) / 이진 탐색 트리 (0) | 2022.04.07 |