자료구조 / 알고리즘/자료구조
[자료구조] Heap
부레두
2022. 12. 29. 12:12
힙 ( Heap )
1) 개념
무엇인가를 차곡차곡 쌓아올린 더미'라는 뜻
- 최댓값 및 최솟값을 찾아내는 연산을 빠르게 하기 위해 고안된 '완전 이진 트리'를 기본으로 한 자료구조
- A가 B의 부모노드면, A의 키 값이 B의 키 값 사이에 대소 관계가 성립 = 힙(Heap)의 속성
- 부모 노드가 최댓값일 경우 '최대 힙', 최솟값일 경우 '최소 힙'
- 대소관계는 오로지 부모와 자식간에만 성립, 형제 사이끼리는 정해지지 않음
- 원소의 정렬이 끝까지 이뤄지지 않고 최대, 최소를 구하는 것만 확실
- 이런 특징을 이용해 '우선순위 큐'와 같은 추상적 자료형을 구현
- 시간 복잡도
- 최소/최대 원소에 접근하는 동작은 O(1)
- 삽입은 O(log n)
- 제거는 최소/최대 원소에 대해서만 가능
2) 이진 힙
- 내부노드에 키와 요소를 저장한 이진 트리
- i번째 노드의 왼쪽 자식노드의 위치는 (2 * i)
- i번째 노드의 오른쪽 자식노드의 위치는 (2 * i + 1)
- i번째 노드의 부모노드의 위치는 (i / 2)
3 - 1) 연산 - 삽입
- 완전 이진 트리를 유지해야함
- 새 요소는 힙의 마지막 노드에 삽입
- 새 노드가 기존 노드보다 크다면 값을 비교하고 교환
- 자식 노드와도 마찬가지로 비교
void insert_max_heap(int x)
{
maxHeap[++heapSize] = x;
for(int i = heapSize; i > 1; i /= 2)
{
// 부모노드와 자기 자신비교해 부모가 작으면 swap
if(maxHeap[i/2] < maxHeap[i])
{
swap(i/2, i);
}
else
break;
}
}
3 - 2) 연산 - 삭제
- 가장 큰(작은) 원소, 루트 노드만 삭제 가능 => 다른 원소에 직접 접근이 불가능 하기 때문
- 루트 노드와 마지막 노드를 교환후 마지막 노드를 삭제
- 루트 노드와 두 자식 노드를 비교 후 더 큰 노드와 서로 교환, 이를 재귀적으로 반복
int delete_max_heap()
{
if(heapSize == 0)
return 0;
int node = maxHeap[1];
maxHeap[1] = maxHeap[heapSize];
maxHeap[heapSize--] = 0;
for(int i = 1; i * 2 <= heapSize;)
{
// 마지막 노드가 왼쪽, 오른쪽 자식 노드보다 크면 끝
if(maxHeap[i] > maxHeap[i*2] && maxHeap[i] > maxHeap[i*2+1])
break;
// 왼쪽이 큰 경우
else if(maxHeap[i*2] > maxHeap[i*2+1])
{
swap(i, i * 2);
i = i*2;
}
// 오른쪽이 큰 경우
else
{
swap(i, i * 2 + 1);
i = i * 2 + 1;
}
}
}
3 - 3) 연산 - 초기화
- 불변성을 유지해야 하기 때문에 초기화가 어렵고 효율적이지 않으나 비어있는 힙에 하나씩 원소를 삽입하는 것
- 힙 생성 알고리즘을 사용
-> 전체 트리의 아래쪽 서브 트리부터 힙 불변성을 만족하도록 힙을 업데이트하는 방식
-> C++ 표준은 배열 또는 벡터의 반복자를 인자로 받아 힙을 구성하는 std::make_heap() 함수를 제공