힙 정렬(Heap Sort)이란?
- 최대 힙 트리나 최소 힙 트리를 구성해 정렬을 하는 방법이다.
작동 방식
[초기 배열]
1) 배열 값 순서대로 부모노드 - 왼쪽 자식 - 오른쪽 자식 순서대로 완전 이진트리를 구성한다.
2) 최대 힙이 되도록 힙을 구성한다.
- 자식 노드를 비교하여 더 큰 값을 찾는다.
- 부모노드보다 큰 지 비교한 후, 부모노드보다 크면 값을 교환한다.
- 루트까지 반복한다.
3) 루트와 마지막 단말 노드(자식이 없는 노드) 값을 교체한 후 노드를 제거한다.
4) 변경된 트리를 다시 최대 힙이 되도록 재구성한다. (2~3 반복)
2~3번 작업을 반복하게 되면, 최대 힙이 되도록 재구성할 때마다 루트에 최댓값이 오게 된다.
4번 작업을 통해 가장 큰 값이 배열의 가장 오른쪽 끝 인덱스부터 차례대로 위치하게 된다.
소스코드
#include <iostream>
using namespace std;
void heapSort(int* arr, int len);
void heapify(int* arr, int len, int parent);
void swap(int& a, int& b);
int main() {
int N;
cin >> N;
int* arr = new int[N + 1];
for (int i = 1; i <= N; i++) {
cin >> arr[i];
}
heapSort(arr, N);
for (int i = 1; i <= N; i++) {
printf("%d\n", arr[i]);
}
delete[] arr;
return 0;
}
void heapSort(int* arr, int len) {
// 최대 힙 구성
for (int i = len / 2; i > 0; i--) {
heapify(arr, len, i);
}
for (int i = len; i > 1; i--) {
// 마지막 노드 교체
swap(arr[1], arr[i]);
// 최대 힙 구성
heapify(arr, i - 1, 1);
}
}
void heapify(int* arr, int size, int parent) {
int left = parent * 2;
int right = parent * 2 + 1;
// 범위를 벗어난 경우
if (right > size && left > size) return;
int max = left;
// 오른쪽 자식도 있는 경우
if (left < size) {
max = arr[left] < arr[right] ? right : left;
}
if (arr[parent] < arr[max]) {
swap(arr[parent], arr[max]);
heapify(arr, size, max);
}
}
void swap(int& a, int& b) {
int temp = a;
a = b;
b = temp;
}
정렬 방식에 대해 이해하고 나서 처음 코드를 짰을 때에는, 시간초과가 걸렸다. (백준 2751번 문제로 체크)
맨 처음 전체적으로 최대 힙으로 구성한 후, 루트와 마지막 노드를 교환했다.
그 다음 다시 최대 힙으로 구성을 하는데 이 과정에서 bottom-up 방식으로 마지막 노드부터 루트 노드까지 전체적으로 비교를 했던 것이다.
하지만 루트와 마지막 노드만 교환한 것이므로 루트노드 ~ 교환된 쪽 방향의 노드들만 비교하면 된다.
시간복잡도
평균의 경우 : O(nlogn)
최선의 경우 : O(nlogn)
최악의 경우 : O(nlogn)
최대 힙으로 구성하는 과정이 트리의 깊이만큼 이루어지므로 O(logn)의 시간이 걸린다.
전체 n개의 데이터에 대해 힙을 재구성하므로 시간복잡도는 O(nlogn)이 된다.
비교
합병 정렬과 힙 정렬은 시간복잡도가 동일하다.
하지만 합병 정렬은 정렬된 데이터를 저장하기 위한 별도의 공간이 필요하다.
빠른 정렬의 최악의 경우 시간복잡도는 O(n2)이지만, 평균적으로 보면 빠른 정렬이 속도가 더 빠르다.
따라서 빠른 정렬 방식이 더 많이 쓰인다.
참고
'Algorithm > 개념' 카테고리의 다른 글
[Algorithm] 동적 계획법 (Dynamic Programming) (0) | 2019.06.11 |
---|---|
[Algorithm] 정렬 - 계수 정렬 (Counting Sort) (0) | 2019.06.08 |
[Algorithm] 정렬 - 빠른 정렬 (Quick Sort) (0) | 2019.05.26 |
[Algorithm] 정렬 - 합병 정렬 (Merge Sort) (0) | 2019.05.24 |
[Algorithm] 정렬 - 선택 정렬 (Selection Sort) (0) | 2019.05.23 |