static void swap(int& first, int& second)
{
int temp = first;
first = second;
second = temp;
}
void sort(std::vector<int>& buf)
{
heapify(buf);
for (int i=(int)buf.size()-1; i>=0; --i)
{
swap(buf[0], buf[i]);
re_heapify(buf, i);
}
}
먼저 전체적인 로직은 들어온 입력 버퍼에 대해 heapify를 수행하고
구해진 최댓값을 맨 뒤의 원소와 swap하고 다시 heapify를 진행한다. (n-1번 반복)
static void heapify(std::vector<int>& buf)
{
for (int i=1; i<(int)buf.size(); ++i)
{
int cur = i;
while (cur > 0)
{
int parent = (cur - 1) / 2;
if (buf[parent] < buf[cur])
swap(buf[parent], buf[cur]);
cur = parent;
}
}
}
heapify()의 구현은 이렇다.
부모의 입장에서 자식과 비교한다면 buffer overflow를 많이 고려해야 하므로, 자식의 입장에서 부모와 비교했다.
0번 index는 루트 노드라 부모가 없기에 1부터 진행한다.
parent의 index를 구해주고 비교하여 swap한다.
이후 새롭게 바뀐 부모 노드와 그 노드의 부모 노드도 비교 해주어야 Heap 구조가 유지된다.
이를 while 문에서 반복하며, 계속 상위 노드로 올라가 비교하고, 자신이 루트 노드가 된다면 중단한다.
static void re_heapify(std::vector<int>& buf, int max)
{
int parent = 0;
while (true)
{
int cur = 2*parent+1;
if (cur >= max)
break;
if (cur+1 < max && buf[cur+1] > buf[cur])
cur = cur+1;
if (buf[parent] < buf[cur])
swap(buf[parent], buf[cur]);
parent = cur;
}
}
최대힙이 완성되고 마지막 요소와 swap된 이후 re_heapify()가 호출되는데
이는 바뀐 루트 노드로부터 두 자식을 비교해 더 큰 쪽과 바꾸고, 바꾼 서브트리로만 내려가며 Heapify를 진행한다.
자식들 중 더 작은 노드는 건들지 않았기 때문에 그 서브트리는 볼 필요가 없기에 최적화한다.