기본 개념
- 히프 정렬은 히프 자료구조의 장점인 최대값을 삭제하거나 임의의 값을 삽입하는 연산을 수월하게 하는 점을 이용한 정렬이다.
히프
- 히프는 완전 이진 나무로 나무의 각 노드의 값은 그 노드가 자식 노드를 갖는 경우에 자식의 값보다 크거나 같아야 한다.
- 각 노드의 값이 자식 노드의 값보다 작거나 같도록 히프를 구성할 수 도 있는데 이를 최소값 히프라 한다.
- 각 노드의 값이 자식 노드의 값보다 크거나 같은 히프는 최대값 히프라고 한다.
히프 정렬은 두 단계로 구성된다.
- 첫째 단계에서 정렬하려는 1차원 배열을 히프로 변환한다.
- 두 번째 단계에서는 가장 큰 값, 두 번째로 큰 값 등을 차례로 히프에서 제거하면서 키를 정렬한다.
첫째 단계. 히프로의 변환 과정
- n개의 키로 구성된 1차원 배열을 히프로 변환하는 방법에는 두 가지 방법이 있다.
첫 번째 방법
- 삽입 정렬과 비슷한 방법을 사용하여 a[0:i-1] 이 이미 히프 구조를 하고 있는 상태에서 a[i]를 정당한 위치에 삽입하여 a[0:i] 역시 히프 구조를 갖도록 한다.
- 즉. a[i] 의 제자리를 찾기 위해 a[i]는 자신의 부모노드와 그 크기가 비교되고, 부모노드보다 크면 부모노드와 자리바꿈을 한 후, 다시 그위의 노드와 비교를 하게 된다.
- 이렇게 트리를 거슬러 올라가면서 자신의 조상 노드들과 자리바꿈을 계속해 가면서 제자리를 찾는다.
두 번째 방법
- 배열 전체를 하나의 완전 이진 트리로 간주하고 잎(leaf) 노드로부터 뿌리(root) 노드에 이르기까지 한 레벨씩 트리를 거슬러 올라가면서 트리의 아래 부분이 히프 구조를 가지도록 하는 것이다.
- n개의 노드를 갖는 완전 이진 나무는 [n/2] 개의 잎 노드를 가지며 이 잎 노드를 뿌리로 하는 [n/2] 개의 노드 한 개짜리 나무들은 이미 각각 작은 히프로 볼 수 있다.
- 이는 1차원 배열 전체를 하나의 트리로 보고 그 트리의 리프가 아니면서 가장 높은 레벨에 있는 노드, 즉 잎을 자식 노드로 갖는 노드부터 시작하여 그 트리의 뿌리에 이르기까지 각 노드를 이미 이루어진 작은 히프들의 뿌리에 삽입하는 것과 같다.
두 번째 단계. 최대값을 제거하며 정렬하고 남은 원소로 반복하여 히프를 구성하는 과정
-히프에서 최대값을 제거하고 남아 있는 원소들 만으로 다시 히프를 구성하는 과정을 n-1회 반복하여 히프 정렬을 진행한다.
코드
void HeapSort(int ary[], int n){
int i;
//1차원 배열을 히프로 변환
// n/2 -> n/2-1 ->...-> 1
//배열 전체를 완전 이진 나무로 간주하고 리프(잎) 노드부터 뿌리노드까지 한 레벨씩 거슬러 올라가면서
//트리 하단 부분부터 히프 구조를 가지도록 함
//n개의 노드를 갖는 완전 이진 노드는 n/2개의 잎 노드를 가짐
printf("--------1차원 배열을 히프로 변환--------\n");
for (i = n / 2; i > 0; i--) {
MakeHeap(ary, i - 1, n - 1);
pirntHeap(ary, 10);
}
printf("-----------남은 원소 히프 구성-----------\n");
//히프에서 최대값을 제거하고
//남은 원소들로 다시 히프 구성 (n-1)회 반복
for (i = n-1 ; i > 0; i--) {
swap(ary[0], ary[i]);
MakeHeap(ary, 0, i - 1);
pirntHeap(ary, 10);
}
}
void MakeHeap(int a[], int root, int lastNode) {
int parent, leftSon, rightSon, son, rootValue;
parent = root;
rootValue = a[root];
leftSon = 2 * parent + 1;
rightSon = leftSon + 1;
while (leftSon <= lastNode) {
if (rightSon <= lastNode && a[leftSon] < a[rightSon])
son = rightSon;
else
son = leftSon;
if (rootValue < a[son]) {
a[parent] = a[son];
parent = son;
leftSon = parent * 2 + 1;
rightSon = leftSon + 1;
}
else break;
}
a[parent] = rootValue;
}
실행 시간
초기 히프 구축 시간 = O(n)
Makeheap에 걸리는 시간 = 뿌리의 높이 = O(lgn)
전체 히프 정렬 시간 복잡도 = O(nlgn)
특징
제자리 정렬
불안정한 정렬
'알고리즘스터디' 카테고리의 다른 글
[알고리즘] 기수 정렬 (Radix Sort) (0) | 2020.08.26 |
---|---|
[알고리즘] 계수 정렬 (Count Sort) (0) | 2020.08.19 |
[알고리즘] 쉘 정렬 (Shell Sort) (0) | 2020.08.10 |
[알고리즘] 퀵 정렬 (Quick Sort) (0) | 2020.08.10 |
[알고리즘] 삽입정렬 (Insertion Sort) (0) | 2020.08.03 |