[C++ 자료 구조와 알고리즘] #9 자료 구조 (9) - std::priority_queue (C++ STL container)

Programming/C++ · 2023. 5. 27. 01:00

안녕하세요. C++을 다루기 위한 기본 적인 자료 구조와 코딩 테스트 등에서 응용될 수 있는 알고리즘을 알아보는 시간을 가지겠습니다.

 

이번 게시물은 std::priority_queue을 간단히 설명해 보려 합니다. 

 

1) 특징

std::priority_queue는 C++ 표준 라이브러리 컨테이너(C++ STL container) 중 하나로, 우선순위 큐를 구현하는 데 사용됩니다. 해당 자료구조에 삽입된 데이터들은 우선순위에 따라 자동으로 정렬됩닌다. 기본적으로 가장 큰 값이 가장 먼저 pop 되도록 정렬되지만, 우선순위를 변경할 수 있습니다. (다음 게시물에서 우선순위 변경법을 설명 드릴게요!) 또한, 이진 힙(Binary Heap)을 사용하여 구현되어 있기 때문에 삽입과 삭제 연산의 시간 복잡도가 O(log N)으로 효율적입니다.
 
이와같은 std::priority_queue에 대한 attributes와 관련 메서드 사용 예시를 알아보겠습니다.

 

2) 코딩 테스트 활용 예시

  • 최대/최소 K개 요소 찾기
    : std::priority_queue를 사용하여 배열을 순회하면서 각 탐색 시점에 가장 크거나 작은 K개의 요소를 std::priority_queue에 저장하고, K개를 넘어가면 우선순위가 가장 낮은 요소를 제거하면서 문제를 해결할 수 있습니다.
  • 정렬된 배열 병합
    : 정렬된 두 개 이상의 배열을 하나의 정렬된 배열로 병합하는 문제입니다. 여러 개의 배열을 std::priority_queue에 저장하고 우선순위에 따라 데이터를 꺼내어 다시 새로운 배열에 저장함으로써 문제를 해결할 수 있습니다.
  • 중복 문자 제거
    : 문자열에서 중복된 문자를 제거하고, 사전 순서로 가장 작은 문자열을 구하는 문제입니다. 문자들을 std::priority_queue에 저장하고, 중복을 제거하면서 가장 작은 문자열을 구할 수 있습니다.
다음은 중복 문자 제거 예시입니다.
#include <iostream>
#include <string>
#include <unordered_set>
#include <queue>

std::string removeDuplicateLetters(const std::string& s) {
    std::unordered_set<char> seen; // 중복 문자 확인을 위한 집합
    std::unordered_map<char, int> count; // 문자의 개수를 저장하는 맵
    std::priority_queue<char, std::vector<char>, std::greater<char>> pq; // 사전식 순서로 가장 작은 문자를 선택하기 위한 우선순위 큐

    // 각 문자의 개수를 세어 맵에 저장
    for (char c : s) {
        count[c]++;
    }

    // 문자열을 순회하며 사전식 순서로 가장 작은 문자 선택
    for (char c : s) {
        count[c]--; // 문자의 개수를 감소

        // 이미 선택된 문자면 건너뛰기
        if (seen.find(c) != seen.end()) {
            continue;
        }

        // 우선순위 큐에 문자 추가
        while (!pq.empty() && pq.top() > c && count[pq.top()] > 0) {
            seen.erase(pq.top()); // 우선순위 큐의 top 요소를 집합에서 제거
            pq.pop(); // 우선순위 큐의 top 요소 제거
        }

        pq.push(c); // 문자 추가
        seen.insert(c); // 선택된 문자 집합에 추가
    }

    // 우선순위 큐의 요소들을 순회하며 결과 문자열 생성
    std::string result;
    while (!pq.empty()) {
        result += pq.top();
        pq.pop();
    }

    return result;
}

int main() {
    std::string s = "bcabc";
    std::string result = removeDuplicateLetters(s);
    std::cout << "Original String: " << s << std::endl;
    std::cout << "Modified String: " << result << std::endl;

    return 0;
}

 

3) 속성 (Attributes)

std::priority_queue는 <priority_queue> 헤더를 포함해서 사용할 수 있습니다.

 

우선 다음과 같은 std::priority_queue의 주요 속성과 멤버 함수를 통해 해당 자료 구조를 활용하는 방법을 자세하게 알아보겠습니다.

 

  • push(const T& value)
    : 우선순위 큐에 요소를 삽입합니다.
  • emplace(Args&&... args)
    : 우선순위 큐에 요소를 생성하여 삽입합니다.
  • pop()
    : 가장 우선순위가 높은 요소를 제거합니다.
  • top()
    : 가장 우선순위가 높은 요소에 접근합니다.
  • size()
    : 우선순위 큐에 저장된 요소의 개수를 반환합니다.
  • empty()
    : 우선순위 큐가 비어 있는지 여부를 확인합니다.
  • swap(priority_queue& other)
    : 두 우선순위 큐를 서로 교환합니다.

 

4) 속성 사용 예시

다음은 std::priority_queue의 속성 사용 예시입니다.

 

#include <iostream>
#include <queue>

int main() {
    std::priority_queue<int> pq;

    // push(element): 요소 삽입
    pq.push(5);
    pq.push(2);
    pq.push(8);

    // top(): 가장 우선순위가 높은 요소에 접근
    std::cout << "Top element: " << pq.top() << std::endl;

    // pop(): 가장 우선순위가 높은 요소 제거
    pq.pop();

    // empty(): 우선순위 큐가 비어 있는지 여부 확인
    if (pq.empty()) {
        std::cout << "Priority queue is empty" << std::endl;
    } else {
        std::cout << "Priority queue is not empty" << std::endl;
    }

    // size(): 우선순위 큐에 저장된 요소의 개수 반환
    std::cout << "Size of priority queue: " << pq.size() << std::endl;

    // swap(): 두 우선순위 큐 교환
    std::priority_queue<int> otherPq;
    otherPq.push(3);
    pq.swap(otherPq);

    return 0;
}
반응형