카테고리 없음

힙 정렬 Heap sort

공대녀J 2023. 8. 31. 17:08

힙 정렬은 힙 트리를 이용한 정렬 방법이다.

힙 트리는 우선순위 큐를 구현하는 데 사용되는 자료구조로,

힙 정렬에서도 우선순위 큐를 이용하면 간단하게 구현 가능하다.

 

1. 힙 트리 

 최대 힙의 경우, 최대값을 root로 두고 이진 트리를 구성하는 트리 구조.

 부모 노드가 자식 노드의 값보다 무조건 큰 값을 갖는다. 

 최소 힙의 경우, 최대 힙의 경우와 반대이다. 

 

 부모 노드 접근 식 : (n - 1) / 2

 n은 현재 노드의 인덱스 값으로, 힙 트리의 경우 이진 트리의 성질을 갖기 때문에 

 데이터 삽입 시, _heap.size() - 1 부터 시작하여 순차적으로 접근한다. 

 

 left 노드 접근 식 : (n * 2) + 1 

 right 노드 접근 식 : (n * 2) + 2

 데이터 삭제 시, 힙 트리의 경우 root의 노드의 데이터를 pop 하기 때문에

 인덱스 0 의 데이터 값을 추출 후, 트리를 정렬해 준다.

 

우선순위 큐 구현

template <typename T, typename Container = vector<int>, typename Predicate = less<T>>
class Priority_queue
{
public:
    void push_back(const T& value)
    {
        _heap.push_back(value);
        int now = (int)_heap.size() - 1;

        while (now > 0)
        {
            int next = (now - 1) / 2;

            if (_predicate(_heap[now] , _heap[next]))
                break;

            ::swap(_heap[now], _heap[next]);
            now = next;

        }
    }

    void pop()
    {
        _heap[0] = _heap.back();
        _heap.pop_back();

        int now = 0;

        while (true)
        {
            int left = (now * 2) + 1;
            int right = (now * 2) + 2;

            //child node가 존재하지 않는 경우
            if ((int)_heap.size() <= left)
                break;

            int next = now;

            if (_predicate(_heap[next] , _heap[left]))
                next = left;

            //둘 중 승자를 오른쪽 노드와 비교
            if ((int)_heap.size() > right && _predicate(_heap[next], _heap[right]))
                next = right;
            
            //노드의 위치가 변경되지 않은 경우
            if (next == now)
                break;

            ::swap(_heap[now], _heap[next]);
            now = next;
        }

    }


    T& top()
    {
        return _heap[0];
    }

    bool empty()
    {
        return _heap.empty();
    }

private:
    Container _heap;
    Predicate _predicate;
};

 

 

힙 정렬은 우선순위 큐를 통해 구현되는 정렬 기법으로 시간 복잡도는 O(NlogN) 이다.

우선순위 큐 사용을 위해 #include <queue> 헤더를 추가해준다.

 

void HeapSort(vector<int>& v)
{
	priority_queue<int, vector<int>, greater<int>> pq;

	//O(NlogN)
	for (int value : v)
		pq.push(value);

	v.clear();

	//O(NlogN)
	while (pq.empty() == false)
	{
		v.push_back(pq.top());
		pq.pop();
	}
}