1. Heapify(힙 생성) 알고리즘
-
i = 1부터 size/2까지 늘려가며 모든 서브트리를 힙구조로 변경
-
i = 1로 설정하는 이유는 Parent & Child의 특수한 관계를 이용하기 위함 (k번째 원소의 부모(k/2), 왼쪽 자식(k*2), 오른쪽 자식(k*2+1) 등. 만약 i = 0부터 시작하면 부모, 왼쪽자식 등이 모두 0이 되기 때문에 연산이 무의미해짐.
-
size/2까지 늘리는 이유는 size/2까지의 노드가 내부노드 (자식노드를 가진 노드)이기 때문
-
좌우 자식 노드(arr[c], arr[c+1]) 중 큰 노드를 고르고, 그 노드의 값이 부모노드보다 크면(arr[c], arr[i]) 둘을 Swap하여 힙 구조를 생성함
2. Heap Sort (힙 정렬) 알고리즘
-
먼저 배열을 최대 힙 구조로 만듬. 최대 힙 구조에서는 가장 첫번째 원소가 가장 큰 값임.
-
때문에 첫번째 원소를 arr의 가장 끝으로 Swap하여, 최대 값을 찾아냄
-
그리고 이미 정렬된 끝부분을 제외한 나머지 부분을 다시 힙구조로 만듬 (heapify 호출)
-
이 것을 계속 반복하여 가장 큰 원소들을 차례대로 뒤에 담으면 정렬이 완성됨.
3. Heap Sort의 특징
- 시간복잡도 : $O(nlogn)$ 그러나 Quick Sort나 Merge Sort보다는 느림.
- 공간복잡도 : 병합정렬 등과 비교해 새로운 배열을 사용하지 않기 때문에 공간복잡도가 우수함.
4. 소스코드
#include <cstdio>
void swap(int *arr, int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
void heapify(int *arr, int size, int i) {
int c = 2 * i + 1;
// 왼쪽 자식 선택
if (c < size - 1 && arr[c] < arr[c + 1])
c++;
// 오른쪽 자식 존재하면서
// 오른쪽 자식이 더 크면 오른쪽 자식 선택
if (c < size && arr[i] < arr[c])
swap(arr, i, c);
// 부모보다 자식이 더 크면
// 둘이 바꿈
if (c < size / 2)
heapify(arr, size, c);
// 내부노드에 한정하여 반복
}
void sort(int *arr, int size) {
for (int i = size / 2; i >= 0; i--) {
heapify(arr, size, i);
}
for (int i = size - 1; i >= 0; i--) {
swap(arr, i, 0);
heapify(arr, i, 0);
}
}
int main() {
int arr[] = {3, 9, 4, 7, 5, 0, 1, 6, 8, 2};
int size = sizeof(arr) / sizeof(arr[0]);
sort(arr, size);
for (int i = 0; i < size; i++) {
printf("%d", arr[i]);
if (i != size - 1) {
printf(" , ");
}
}
return 0;
}
4. Reference
'알고리즘' 카테고리의 다른 글
정렬 (14) - 총정리 (0) | 2020.02.12 |
---|---|
정렬 (13) - 기수 정렬 (Radix Sort) (0) | 2020.02.12 |
정렬 (12) - 계수 정렬 (Counting Sort) (0) | 2020.02.12 |
정렬 (10) - 힙 정렬 (Heap Sort) (1) (0) | 2020.02.12 |
정렬 (9) - 병합 정렬 (Merge Sort) (0) | 2020.02.12 |
정렬 (8) - 쉘 정렬 (Shell Sort) (0) | 2020.02.11 |
정렬 (7) - 개선된 퀵 정렬 (Improved Quick Sort) (0) | 2020.02.11 |