우선순위 큐 (priority_queue)

Crat3 ㅣ 2023. 10. 5. 18:07

1. 우선순위 큐 (priority_queue)

데이터를 큐에 넣을 때 자동으로 내림차순(혹은 오름차순)으로 정렬되어 들어간다.

우선순위 큐는 힙 트리로 구성되어있다.

 

2. 힙 트리 (Heap Tree)

이진 트리로 구성되어 있음.

부모 노드의 데이가 자식 노드보다 항상 크거나(최대 힙), 항상 작은(최소 힙) 트리.

-> 정렬되어 있는 이진 트리

 

3. 힙 트리의 조건

1) 힙 트리는 반드시 최대 힙 또는 최소 힙이어야 한다.

- 자식 트리 간의 서열은 없다.

 

2) 노드 개수를 알면 트리 구조는 확정할 수 있다.

- 완전 이진 트리 ; 마지막 레벨을 제외한 모든 레벨이 노드가 꽉 차있어야 한다(균형을 이룸).

- 마지막 레벨에 노드가 있다면, 트리의 왼쪽부터 순서대로 채운다.

 

4. 힙 트리의 규칙성

1) i 번째 노드의 왼쪽 자식의 인덱스는 (2 * i) + 1

2) i 번째 노드의 오른쪽 자식의 인덱스는 (2 * i) + 2

3) i 번째 노드의 왼쪽 자식의 인덱스는 (i - 1) / 2

 

5. 새로운 값이 추가되는 상황

1) 트리의 맨 좌측에 값을 추가

 

2) 최대 힙(또는 최소 힙) 조건에 따라 정렬

 

6. 최대값 추출하기

(1) root 트리를 제거(pop)한다.

(2) 최하위 노드(leaf)노드를 root로 옮긴다.

(3) 데이터를 재정렬한다.

 

 

7. 코드

더보기
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;

template<typename T>
class PriorityQueue
{
public:

    void push(const T& data)
    {
        _heap.push_back(data);

        // 정렬 시작
        int now = static_cast<int>(_heap.size()) - 1;

        // 루트 노드까지 도달하기
        while (now > 0)
        {
            int next = (now - 1) / 2;

            if (_heap[now] < _heap[next])
                break;

            // 데이터 교체하기
            std::swap(_heap[now], _heap[next]);

            // 부모로 올라갔으면 인덱스를 대체해주기
            now = next;
        }
    }

    void pop()
    {
        // 데이터(->루트) 교체
        _heap[0] = _heap.back();
        _heap.pop_back();
        
        int now = 0;

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

            // 리프에 도달시 종료
            if (left >= (int)_heap.size())
                break;

            int next = now;

            // 왼쪽과 비교
            if (_heap[next] < _heap[left])
                next = left;

            // 왼쪽과 자신의 승자를 오른쪽과 비교하기
            if (right < _heap.size() && _heap[next] < _heap[right])
                next = right;

            // 왼쪽과 오른쪽 둘 다 현재 값보다 작으면 종료하기
            if (next == now)
                break;

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

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

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

private:
    vector<T> _heap;
};

'복습' 카테고리의 다른 글

함수 객체 ( functor ; 펑터 )  (0) 2023.10.06
함수 포인터  (0) 2023.10.06
가위 바위 보  (0) 2023.08.07
산술연산 시 주의점  (0) 2023.08.07
16진법과 2진법의 관계  (0) 2023.08.07