khai báo một priority_queue trong c ++ với một bộ so sánh tùy chỉnh


83

Tôi đang cố gắng khai báo a priority_queue of nodes, sử dụng bool Compare(Node a, Node b)làm hàm so sánh (nằm ngoài lớp nút).

Những gì tôi hiện có là:

priority_queue<Node, vector<Node>, Compare> openSet;

Vì một số lý do, tôi nhận được Error: "Compare" is not a type name

Thay đổi khai báo thành priority_queue <Node, vector<Node>, bool Compare>

đưa cho tôi Error: expected a '>'

Tôi cũng đã thử:

priority_queue<Node, vector<Node>, Compare()> openSet;
priority_queue<Node, vector<Node>, bool Compare()> openSet;
priority_queue<Node, vector<Node>, Compare<Node, Node>> openSet; 

Tôi nên khai báo chính xác priority_queuenhư thế nào?

Câu trả lời:


110

Bạn nên khai báo một lớp Comparevà nạp chồng operator()cho nó như thế này:

class Foo
{

};

class Compare
{
public:
    bool operator() (Foo, Foo)
    {
        return true;
    }
};

int main()
{
    std::priority_queue<Foo, std::vector<Foo>, Compare> pq;
    return 0;
}

Hoặc, nếu bạn vì một số lý do không thể xếp nó thành lớp học, bạn có thể sử dụng std::functionnó:

class Foo
{

};

bool Compare(Foo, Foo)
{
    return true;
}

int main()
{
    std::priority_queue<Foo, std::vector<Foo>, std::function<bool(Foo, Foo)>> pq(Compare);
    return 0;
}

1
Hoàn hảo, đúng như những gì tôi đang tìm kiếm. Tôi chưa bao giờ nghĩ sẽ tạo ra một lớp học riêng biệt. Ví dụ đầu tiên có được coi là phong cách tốt hơn không?
Steven Morad

2
@StevenMorad, tôi thích sử dụng lớp có quá tải hơn operator(), nó trông đơn giản hơn.
awesoon

1
@soon Tại sao chúng ta quá tải toán tử ()? Điều này có được liên kết với cách ưu tiên_ hàng đợi được triển khai nội bộ không? quá tải> hoặc <có ý nghĩa trực quan, nhưng toán tử () không quá nhiều
Piyush

2
@Piyush, câu hỏi là về việc chuyển một bộ so sánh tùy chỉnh cho pritority_queue. Có thể quá tải operator<và sử dụng bộ std::lessso sánh tích hợp, tuy nhiên, được bool Compare(Node a, Node b)khai báo bên ngoài lớp Node, theo câu hỏi.
chờ

1
Tôi tiếp tục quay lại câu trả lời này, có lẽ như 50 lần bây giờ, tôi không bao giờ nhớ được cú pháp
Rockstar5645

48

Câu trả lời được chấp nhận khiến bạn tin rằng bạn phải sử dụng một lớp hoặc một bộ std::functionso sánh. Đây không phải là sự thật! Như câu trả lời của cute_ptr cho thấy, bạn có thể chuyển một con trỏ hàm đến hàm tạo. Tuy nhiên, cú pháp để làm như vậy đơn giản hơn nhiều so với được hiển thị ở đó:

class Node;
bool Compare(Node a, Node b);

std::priority_queue<Node, std::vector<Node>, decltype(&Compare)> openSet(Compare);

Có nghĩa là, không cần phải mã hóa rõ ràng kiểu của hàm, bạn có thể để trình biên dịch làm điều đó cho bạn bằng cách sử dụng decltype.

Điều này rất hữu ích nếu bộ so sánh là lambda. Bạn không thể chỉ định loại lambda theo bất kỳ cách nào khác ngoài việc sử dụng decltype. Ví dụ:

auto compare = [](Node a, Node b) { return a.foo < b.foo; }
std::priority_queue<Node, std::vector<Node>, decltype(compare)> openSet(compare);

1
Điều này thật tuyệt vời, tôi tự hỏi liệu có bất kỳ bẫy (vấn đề) tiềm ẩn nào ở đây không. Rất thích xem câu trả lời này có được nhiều khả năng hiển thị và thảo luận hơn.
Apollys hỗ trợ Monica 10/1218

1
@Apollys: Tôi sử dụng phương pháp này thường xuyên (thường Comparelà lambda, không thể viết khai báo cho), tôi không biết có bẫy nào.
Cris Luengo

Nếu bạn làm điều này cho một hàm lambda, bạn sẽ đặt phần thân của hàm lambda ở đâu? Bạn có lưu trữ trước nó trong một biến fvà sau đó thay thế Comparebằng fkhông?
Eric Auld

@EricAuld: Có, Comparecó thể là một hàm lambda ở đó, như trong auto Compare = [](){};. Nhưng bạn cần phải sử dụng decltype(Compare), hơn là decltype(&Compare).
Cris Luengo

Xin chào Chris, điều này thật tuyệt, tôi đang tìm một số định dạng để sử dụng với kiểu khai báo cho priority_queue và không cần khai báo lớp, bạn đã đưa ra câu trả lời hoàn hảo! Cảm ơn!
Amanda Wang

16

Tham số mẫu thứ ba phải là một lớp đã operator()(Node,Node)quá tải. Vì vậy, bạn sẽ phải tạo một lớp theo cách này:

class ComparisonClass {
    bool operator() (Node, Node) {
        //comparison code here
    }
};

Và sau đó bạn sẽ sử dụng lớp này làm tham số mẫu thứ ba như sau:

priority_queue<Node, vector<Node>, ComparisonClass> q;

13
Phương thức toán tử phải là công khai.
knozi

Mẫu thứ ba không cần phải là một lớp. Nó có thể là kiểu của một hàm.
Cris Luengo

Theo cpluplus : Đây có thể là một con trỏ hàm hoặc đối tượng hàm
Benav

9

Trả lời câu hỏi của bạn trực tiếp:

Tôi đang cố gắng khai báo một priority_queuetrong số các nút, sử dụngbool Compare(Node a, Node b) as the comparator function

Những gì tôi hiện có là:

priority_queue<Node, vector<Node>, Compare> openSet;

Vì một số lý do, tôi nhận được Lỗi:

"Compare" is not a type name

Trình biên dịch đang cho bạn biết chính xác điều gì sai: Comparekhông phải là tên kiểu, mà là một thể hiện của một hàm nhận hai Nodesvà trả về a bool.
Những gì bạn cần là chỉ định loại con trỏ hàm:
std::priority_queue<Node, std::vector<Node>, bool (*)(Node, Node)> openSet(Compare)


Đây chính xác là những gì tôi đang tìm kiếm để cung cấp một hàm trong khai báo priority_queue, cảm ơn!
Amanda Wang

4

Người ta cũng có thể sử dụng một hàm lambda.

auto Compare = [](Node &a, Node &b) { //compare };
std::priority_queue<Node, std::vector<Node>, decltype(Compare)> openset(Compare);

2

Trong trường hợp điều này giúp bất kỳ ai:

static bool myFunction(Node& p1, Node& p2) {}
priority_queue <Node, vector<Node>, function<bool(Node&, Node&)>> pq1(myFunction);

2

Bạn phải xác định so sánh trước. Có 3 cách để làm điều đó:

  1. sử dụng lớp học
  2. sử dụng struct (giống như class)
  3. sử dụng hàm lambda.

Thật dễ dàng để sử dụng class / struct vì dễ khai báo chỉ cần viết dòng mã này phía trên mã thực thi của bạn

struct compare{
  public:
  bool operator()(Node& a,Node& b) // overloading both operators 
  {
      return a.w < b.w: // if you want increasing order;(i.e increasing for minPQ)
      return a.w > b.w // if you want reverse of default order;(i.e decreasing for minPQ)
   }
};

Mã gọi:

priority_queue<Node,vector<Node>,compare> pq;

0

thích cấu trúc hơn và đó là những gì std :: lớn hơn làm

struct Compare {
  bool operator()(Node const&, Node &) {}
}
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.