프로그래밍 대회에서 배우는 알고리즘 문제해결 전략 책 내용 정리입니다.
우선순위큐: 우선순위 높은 것을 먼저 삭제하는 큐
구현: 힙으로 하면 좋다
힙의 목적: 가장 큰/작은 원소 빠르게 찾기
힙의 규칙:
우선순위 큐
배열/연결리스트
삽입:
삭제: : 모든 원소 순회하며 우선순위가 가장 높은 것 찾음
균형잡힌 이진 검색 트리
원소들을 우선순위로 정렬해둔다.
삽입, 삭제:
힙 (heap)
가장 큰(작은) 원소를 찾는 데 최적화된 이진 트리
삽입, 삭제:
표준 라이브러리에 구현되어 있다.
힙
특정 규칙을 만족하도록 구성된 이진 트리
최대 원소를 가능한 빠르게 찾을 수 있는 방법으로 설계
→ 단순한 알고리즘으로 효율적 동작
대소 관계 규칙: 부모 노드가 가진 원소는 항상 자식 노드가 가진 원소 이상이다.
균형잡기 규칙
마지막 레벨을 제외한 모든 레벨에 노드가 꽉 차 있어야 한다.
마지막 레벨에 노드가 있을 때는 항상 왼쪽부터 순서대로 채워져 있어야 한다.
cf) level: 높이가 같은 노드들의 집합
cf) 힙의 높이는
A[ (i-1) / 2 ]
/
A[i]
/ \
A[2i + 1] A[2i + 2]
벡터로 구현 가능.
모양 규칙을 먼저 만족→ 대소 규칙 만족
while문 내부가 한 번 수행될 때마다 트리에서 한 레벨 위로 올라감
∴ : 트리의 높이와 같다
while문 내부가 한 번 수행될 때마다 트리에서 한 레벨 아래로 내려감
∴ : 트리의 높이와 같다
힙 만들기
힙 정렬
이미 힙에 들어 있는 원소 중 하나 증가시키기
이진 검색 트리로 풀어도 되지만 구현이 복잡하다...
[힙으로 풀기]
숫자들을 정렬
앞의 절반을 최대 힙, 뒤의 절반을 최소 힙에 넣음
수열 길이가 홀수라면 최대 힙에 하나 더 넣음
그러면 다음을 만족
그러면 이 수열의 중간 값은 최대 힙의 루트에 있음
삽입
숫자를 하나만 추가했으므로 한 번만 숫자들을 바꿔도 2번 불변식 유지 가능
C++ STL priority_queue를 사용해보자.
//코드 23.4 힙을 이용해 변화하는 중간 값 문제를 해결하는 함수의 구현
int runningMedian(int n, RNG rng> {
priority_queue<int, vector<int>, less<int> > maxHeap;
priority„queue<int, vector<int>, greater<int> > minHeap;
int ret = 0;
// 반복문 불변식:
// 1. maxHeap의 크기는 minHeap의 크기와 같거나 1 더 크다.
// 2. maxHeap.topO (= minHeap.topO
for(int cnt = 1; cnt <= n; ++cnt) {
// 우선 l 번 불변식부터 만족시킨다.
if(maxHeap.size() == minHeap. sizeO)
maxHeap.push (rng .: next ()};
else
minHeap.push(rng.next(》);
// 2번 불변식 이 깨졌을 경우 복구하자.
if(!minHeap.empty() && ImaxHeap.empty() && minHeap.top() < maxHeap.top()) {
int a = maxHeap.top(), b = minHeap.top();
maxHeap.pop(); minHeap.popO;
maxHeap.push(b);
minHeap.push(a);
}
ret = (ret + maxHeap.topO) % 20090711;
}
return ret;
}
[시간복잡도]
for 문 내부의 수행 시간을 힙의 추가/삭제 연산이 지배
∴