Làm thế nào để sử dụng STL hàng đợi ưu tiên cho các đối tượng?


80
class Person
{
public:
    int age;
};

Tôi muốn lưu trữ các đối tượng của lớp Person trong một hàng đợi ưu tiên.

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

Tôi nghĩ rằng tôi cần phải xác định một lớp cho thứ so sánh, nhưng tôi không chắc về nó.

Ngoài ra, khi chúng tôi viết,

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

Làm thế nào để lớn hơn hoạt động?


Bài đăng tương tự ở đây
Rick Smith

Câu trả lời:


110

Trong trường hợp này, bạn cần cung cấp so sánh thứ tự yếu nghiêm ngặt hợp lệ cho loại được lưu trữ trong hàng đợi Person. Mặc định là sử dụng std::less<T>, giải quyết thành một cái gì đó tương đương với operator<. Điều này phụ thuộc vào loại được lưu trữ của riêng nó có một. Vì vậy, nếu bạn thực hiện

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

nó sẽ hoạt động mà không có bất kỳ thay đổi nào khác. Việc thực hiện có thể là

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

Nếu loại không có so sánh tự nhiên "nhỏ hơn", sẽ hợp lý hơn nếu cung cấp vị từ của riêng bạn, thay vì mặc định std::less<Person>. Ví dụ,

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

sau đó khởi tạo hàng đợi như sau:

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

Liên quan đến việc sử dụng std::greater<Person>as so sánh, điều này sẽ sử dụng tương đương operator>và có tác dụng tạo hàng đợi với WRT ngược ưu tiên trong trường hợp mặc định. Nó sẽ yêu cầu sự hiện diện của một operator>có thể hoạt động trên hai Persontrường hợp.


7
Trong khi câu trả lời này là đúng, tôi không thích việc sử dụng operator<ở đây. operator<thực hiện so sánh mặc định cho một kiểu, theo kinh nghiệm của tôi, hiếm khi là điều bạn muốn. Tôi nghĩ cách tiếp cận mà Mike mô tả trong câu trả lời của anh ấy hầu như luôn thích hợp hơn.
Björn Pollex

1
@ BjörnPollex Đồng ý. Tôi đã thêm một cái gì đó về điều đó. Trong một lớp chỉ có một thành viên dữ liệu, toán tử có thể có lý.
juanchopanza

Đáng lưu ý: việc triển khai bool YourClass::operator <(const YourClass&) constcũng sẽ cho phép sử dụng minh bạch bộ so sánh mặc định , std::less<T>. Không linh hoạt, nhưng hoạt động khi đó là tất cả những gì bạn cần. (và +1).
WhozCraig

Cảm ơn vì câu trả lời. Tôi có thể nạp chồng toán tử '<' ngay cả khi lớp có nhiều thành viên, phải không?
user2441151

@ user2441151 Có, bạn có thể, nhưng bạn phải cẩn thận với logic. Nó phải thực hiện một trật tự yếu nghiêm ngặt. Dữ liệu càng nhiều thành viên thì càng dễ sai. Đó là trừ khi bạn sử dụng std::tie, trong trường hợp đó thì nó khá tầm thường.
juanchopanza

50

Bạn sẽ viết một lớp so sánh, ví dụ:

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;
    }
};

và sử dụng nó làm đối số so sánh:

priority_queue<Person, vector<Person>, CompareAge>

Việc sử dụng greatercung cấp thứ tự ngược lại với mặc định less, có nghĩa là hàng đợi sẽ cung cấp cho bạn giá trị thấp nhất chứ không phải cao nhất.


1
Có thể truyền "đối tượng so sánh" thay vì các lớp so sánh không? (theo thứ tự để parametrize nó và có được linh hoạt hơn)
castarco

1
@castarco vâng, bạn có thể chuyển một đối tượng so sánh cụ thể làm đối số phương thức khởi tạo.
Mike Seymour

Đây là một phương pháp thích hợp hơn cho câu trả lời hàng đầu. Không chỉ vì nó đạt được sự so sánh cấp cao hơn (có thể dễ dàng chuyển sang các ngôn ngữ khác, cấp thấp hơn và cao hơn), mà còn vì nó dẫn đến nhiều mã có thể tái sử dụng hơn.
Furkan Toprak

20

Hàng đợi ưu tiên là một kiểu dữ liệu trừu tượng nắm bắt ý tưởng về một vùng chứa có các phần tử có "mức độ ưu tiên" được gắn vào chúng. Phần tử có mức độ ưu tiên cao nhất luôn xuất hiện ở đầu hàng đợi. Nếu phần tử đó bị xóa, phần tử có mức độ ưu tiên cao nhất tiếp theo sẽ tiến lên phía trước.

Thư viện tiêu chuẩn C ++ định nghĩa một lớp ưu tiên mẫu, với các hoạt động sau:

push : Chèn một phần tử vào hàng đợi prioity.

top : Trả lại (mà không xóa nó) phần tử có mức ưu tiên cao nhất khỏi hàng đợi ưu tiên.

pop : Xóa phần tử có mức ưu tiên cao nhất khỏi hàng đợi ưu tiên.

size : Trả về số phần tử trong hàng đợi ưu tiên.

rỗng : Trả về true hoặc false tùy theo việc hàng đợi ưu tiên có trống hay không.

Đoạn mã sau cho biết cách tạo hai hàng đợi ưu tiên, một hàng có thể chứa số nguyên và một hàng khác có thể chứa chuỗi ký tự:

#include <queue>

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

Sau đây là một ví dụ về việc sử dụng hàng đợi ưu tiên:

#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;
}

Đầu ra của chương trình này là:

the quick
the lazy dog
jumped over
fox

Vì hàng đợi tuân theo quy luật ưu tiên, các chuỗi được in từ mức ưu tiên cao nhất đến thấp nhất.

Đôi khi người ta cần tạo một hàng đợi ưu tiên để chứa các đối tượng do người dùng xác định. Trong trường hợp này, hàng đợi ưu tiên cần biết tiêu chí so sánh được sử dụng để xác định đối tượng nào có mức ưu tiên cao nhất. Điều này được thực hiện nhờ một đối tượng hàm thuộc một lớp nạp chồng toán tử (). Quá tải () hoạt động như <với mục đích xác định mức độ ưu tiên. Ví dụ, giả sử chúng ta muốn tạo một hàng đợi ưu tiên để lưu trữ các đối tượng Thời gian. Đối tượng Thời gian có ba trường: giờ, phút, giây:

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;
    }
}

Hàng đợi ưu tiên để lưu trữ thời gian theo tiêu chí so sánh ở trên sẽ được định nghĩa như sau:

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;
}

Chương trình in các thời gian từ muộn nhất đến sớm nhất:

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

Nếu chúng tôi muốn thời gian sớm nhất có mức độ ưu tiên cao nhất, chúng tôi sẽ xác định lại CompareTime như sau:

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
Tôi có một câu hỏi, nếu tôi có thể. priority_queue <Thời gian, vectơ <Thời gian>, Thời gian so sánh> pq; . Tại sao tham số thứ hai, vector <Thời gian> lại cần thiết? Tôi đã nhìn thấy nó trong nhiều đoạn mã nhưng tôi không thể hiểu được.
BarbuDorel

Ồ không ... cáo không nâu và cáo không nâu đã nhảy (nhảy) qua con chó lười biếng. :-(
cyber_raj 14/09/16

3
Pq.front () không nên là pq.top () trong đoạn mã đầu tiên?
codewing

4

Đoạn mã này có thể giúp ..

#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();
    }
}

Đầu ra:

22 prashantonly
22 prashant
23 prashantandsoon..

0

Chúng tôi có thể xác định bộ so sánh do người dùng xác định: Đoạn mã dưới đây có thể hữu ích cho bạn.

Đoạn mã:

#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;
}

đầu vào :

batman 2
goku 9
mario 4

Đầu ra

goku 9
mario 4
batman 2

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.