객체에 우선 순위 대기열 STL을 사용하는 방법은 무엇입니까?


80
class Person
{
public:
    int age;
};

Person 클래스의 개체를 우선 순위 대기열에 저장하고 싶습니다.

priority_queue< Person, vector<Person>, ??? >

비교를 위해 클래스를 정의해야한다고 생각하지만 확실하지 않습니다.

또한 우리가 쓸 때

priority_queue< int, vector<int>, greater<int> > 

더 큰 것은 어떻게 작동합니까?


유사 포스트 여기
릭 스미스

답변:


110

Person이 경우 큐에 저장된 유형에 대해 유효한 엄격한 약한 순서 비교를 제공해야합니다 . 기본값 std::less<T>은를 사용 하는 것이며 operator<. 이것은 하나가있는 자체 저장 유형에 의존합니다. 그래서 구현한다면

bool operator<(const Person& lhs, const Person& rhs); 

추가 변경없이 작동합니다. 구현은

bool operator<(const Person& lhs, const Person& rhs)
{
  return lhs.age < rhs.age;
}

유형에 자연스러운 "보다 작음"비교가없는 경우 기본값 대신 자체 조건자를 제공하는 것이 더 합리적 std::less<Person>입니다. 예를 들면

struct LessThanByAge
{
  bool operator()(const Person& lhs, const Person& rhs) const
  {
    return lhs.age < rhs.age;
  }
};

그런 다음 다음과 같이 큐를 인스턴스화하십시오.

std::priority_queue<Person, std::vector<Person>, LessThanByAge> pq;

std::greater<Person>비교기로 의 사용과 관련하여 이것은 operator>기본 사례 인 우선 순위가 반전 된 WRT로 대기열을 생성하는 것과 동등한 것을 사용 하고 효과를 갖습니다. operator>Person인스턴스에서 작동 할 수있는 이 있어야합니다 .


7
이 대답은 정확하지만 operator<여기서 사용하는 것을 싫어합니다 . operator<내 경험상 거의 원하지 않는 유형에 대한 기본 비교를 구현합니다. 나는 Mike가 그의 대답에서 설명하는 접근 방식이 거의 항상 바람직하다고 생각합니다.
Björn Pollex 2013 년

1
@ BjörnPollex 동의합니다. 나는 그것에 대해 뭔가를 추가하고 있었다. 데이터 멤버가 하나만있는 클래스에서는 연산자 의미 가있을 수 있습니다.
juanchopanza

주목할만한 점 : 구현 bool YourClass::operator <(const YourClass&) const하면 기본 비교기 인 std::less<T>. 유연하지는 않지만 필요한 모든 기능을 제공합니다. (및 +1).
WhozCraig

답변 해주셔서 감사합니다. 클래스에 여러 멤버가 있어도 '<'연산자를 오버로드 할 수 있습니다. 그렇죠?
user2441151

@ user2441151 예, 할 수 있지만 논리에주의해야합니다. 엄격한 약한 순서를 구현해야합니다. 데이터 멤버가 많을수록 오류가 발생하기 쉽습니다. 를 사용하지 않는 한 std::tie,이 경우 매우 사소합니다.
juanchopanza

50

예를 들어 비교기 클래스를 작성합니다.

struct CompareAge {
    bool operator()(Person const & p1, Person const & p2) {
        // return "true" if "p1" is ordered before "p2", for example:
        return p1.age < p2.age;
    }
};

이를 비교기 인수로 사용하십시오.

priority_queue<Person, vector<Person>, CompareAge>

를 사용 greater하면 default less와 반대 순서가 지정됩니다. 즉, 대기열이 가장 높은 값이 아닌 가장 낮은 값을 제공합니다.


1
비교기 클래스 대신 "비교 객체"를 전달할 수 있습니까? (매개 변수화하고 더 많은 유연성을 확보하기 위해)
castarco 2014

1
@castarco 예, 특정 비교기 개체를 생성자 인수로 전달할 수 있습니다.
Mike Seymour

이것은 상위 답변보다 더 선호되는 방법입니다. 더 높은 수준의 비교 (다른 언어, 더 낮은 수준 및 더 높은 수준으로 쉽게 전송할 수 있음)를 달성 할뿐만 아니라 더 재사용 가능한 코드를 생성하기 때문입니다.
Furkan 토프 락

20

우선 순위 큐는 요소에 "우선 순위"가 첨부 된 컨테이너의 아이디어를 캡처하는 추상 데이터 유형입니다. 우선 순위가 가장 높은 요소는 항상 대기열 맨 앞에 나타납니다. 해당 요소가 제거되면 다음으로 우선 순위가 높은 요소가 앞으로 이동합니다.

C ++ 표준 라이브러리는 다음 작업으로 priority_queue 클래스 템플릿을 정의합니다.

push : 우선 순위 큐에 요소를 삽입합니다.

top : 우선 순위 큐에서 가장 높은 우선 순위 요소를 (제거하지 않고) 반환합니다.

pop : 우선 순위 대기열에서 우선 순위가 가장 높은 요소를 제거합니다.

size : 우선 순위 큐의 요소 수를 반환합니다.

empty : 우선 순위 큐가 비어 있는지 여부에 따라 true 또는 false를 반환합니다.

다음 코드 스 니펫은 정수를 포함 할 수있는 큐와 문자열을 포함 할 수있는 큐, 두 개의 우선 순위 큐를 구성하는 방법을 보여줍니다.

#include <queue>

priority_queue<int> q1;
priority_queue<string> q2;

다음은 우선 순위 대기열 사용의 예입니다.

#include <string>
#include <queue>
#include <iostream>

using namespace std;  // This is to make available the names of things defined in the standard library.

int main()
{
    piority_queue<string> pq; // Creates a priority queue pq to store strings, and initializes the queue to be empty.

    pq.push("the quick");
    pq.push("fox");
    pq.push("jumped over");
    pq.push("the lazy dog");

    // The strings are ordered inside the priority queue in lexicographic (dictionary) order:
    // "fox", "jumped over", "the lazy dog", "the quick"
    //  The lowest priority string is "fox", and the highest priority string is "the quick"

    while (!pq.empty()) {
       cout << pq.top() << endl;  // Print highest priority string
       pq.pop();                    // Remmove highest priority string
    }

    return 0;
}

이 프로그램의 출력은 다음과 같습니다.

the quick
the lazy dog
jumped over
fox

대기열은 우선 순위 규칙을 따르기 때문에 문자열은 가장 높은 우선 순위에서 가장 낮은 우선 순위로 인쇄됩니다.

때로는 사용자 정의 개체를 포함하기 위해 우선 순위 대기열을 만들어야합니다. 이 경우 우선 순위 대기열은 가장 높은 우선 순위를 갖는 개체를 결정하는 데 사용되는 비교 기준을 알아야합니다. 이는 연산자 ()를 오버로드하는 클래스에 속하는 함수 객체를 통해 수행됩니다. 오버로드 된 ()은 우선 순위를 결정할 목적으로 <역할을합니다. 예를 들어, Time 객체를 저장하기 위해 우선 순위 대기열을 생성한다고 가정합니다. Time 객체에는시, 분, 초의 세 가지 필드가 있습니다.

struct Time {
    int h; 
    int m; 
    int s;
};

class CompareTime {
    public:
    bool operator()(Time& t1, Time& t2) // Returns true if t1 is earlier than t2
    {
       if (t1.h < t2.h) return true;
       if (t1.h == t2.h && t1.m < t2.m) return true;
       if (t1.h == t2.h && t1.m == t2.m && t1.s < t2.s) return true;
       return false;
    }
}

위의 비교 기준에 따라 시간을 저장하는 우선 순위 대기열은 다음과 같이 정의됩니다.

priority_queue<Time, vector<Time>, CompareTime> pq;

Here is a complete program:

#include <iostream>
#include <queue>
#include <iomanip>

using namespace std;

struct Time {
    int h; // >= 0
    int m; // 0-59
    int s; // 0-59
};

class CompareTime {
public:
    bool operator()(Time& t1, Time& t2)
    {
       if (t1.h < t2.h) return true;
       if (t1.h == t2.h && t1.m < t2.m) return true;
       if (t1.h == t2.h && t1.m == t2.m && t1.s < t2.s) return true;
       return false;
    }
};

int main()
{
    priority_queue<Time, vector<Time>, CompareTime> pq;

    // Array of 4 time objects:

    Time t[4] = { {3, 2, 40}, {3, 2, 26}, {5, 16, 13}, {5, 14, 20}};

    for (int i = 0; i < 4; ++i)
       pq.push(t[i]);

    while (! pq.empty()) {
       Time t2 = pq.top();
       cout << setw(3) << t2.h << " " << setw(3) << t2.m << " " <<
       setw(3) << t2.s << endl;
       pq.pop();
    }

    return 0;
}

이 프로그램은 최근 시간부터 가장 빠른 시간까지 인쇄합니다.

5  16  13
5  14  20
3   2  40
3   2  26

가장 빠른 시간에 가장 높은 우선 순위를 지정하려면 다음과 같이 CompareTime을 재정의합니다.

class CompareTime {
public:
    bool operator()(Time& t1, Time& t2) // t2 has highest prio than t1 if t2 is earlier than t1
    {
       if (t2.h < t1.h) return true;
       if (t2.h == t1.h && t2.m < t1.m) return true;
       if (t2.h == t1.h && t2.m == t1.m && t2.s < t1.s) return true;
       return false;
    }
};

1
할 수 있다면 질문이 있습니다. priority_queue <시간, 벡터 <시간>, CompareTime> pq; . 두 번째 매개 변수 인 vector <Time>이 필요한 이유는 무엇입니까? 나는 수많은 코드 조각에서 그것을 보았지만 이해할 수 없었다.
BarbuDorel

오 안돼 ... 여우는 갈색이 아니고 갈색이 아닌 여우는 게으른 개 위로 뛰어 올랐다 (점프). :-(
cyber_raj

3
첫 번째 스 니펫에서 pq.front ()가 pq.top ()이어야하지 않습니까?
codewing

4

이 코드가 도움이 될 수 있습니다 ..

#include <bits/stdc++.h>
using namespace std;    

class node{
public:
    int age;
    string name;
    node(int a, string b){
        age = a;
        name = b;
    }
};

bool operator<(const node& a, const node& b) {

    node temp1=a,temp2=b;
    if(a.age != b.age)
        return a.age > b.age;
    else{
        return temp1.name.append(temp2.name) > temp2.name.append(temp1.name);
    }
}

int main(){
    priority_queue<node> pq;
    node b(23,"prashantandsoon..");
    node a(22,"prashant");
    node c(22,"prashantonly");
    pq.push(b);
    pq.push(a);
    pq.push(c);

    int size = pq.size();
    for (int i = 0; i < size; ++i)
    {
        cout<<pq.top().age<<" "<<pq.top().name<<"\n";
        pq.pop();
    }
}

산출:

22 prashantonly
22 prashant
23 prashantandsoon..

0

사용자 정의 비교기를 정의 할 수 있습니다 :. 아래 코드가 도움이 될 수 있습니다.

코드 스 니펫 :

#include<bits/stdc++.h>
using namespace std;

struct man
{
  string name;
  int priority; 
};

class comparator
{
 public:
   bool operator()(const man& a, const man& b)
   {
        return a.priority<b.priority;
   }
};

int main()
{
   man arr[5];
   priority_queue<man, vector<man>, comparator> pq;

   for(int i=0; i<3; i++)
   {
     cin>>arr[i].name>>arr[i].priority;
     pq.push(arr[i]);
   }

   while (!pq.empty())
   {
     cout<<pq.top().name<<" "<<pq.top().priority;
     pq.pop();
     cout<<endl;
   }
   return 0;
}

입력 :

배트맨 2
손오공 9
마리오 4

산출

손오공 9
마리오 4
배트맨 2

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.