özel bir karşılaştırıcı ile c ++ 'da bir öncelikli kuyruğun bildirilmesi


88

Karşılaştırıcı işlevi olarak (düğüm sınıfının dışında olan) priority_queue of nodeskullanarak a bildirmeye çalışıyorum bool Compare(Node a, Node b).

Şu anda sahip olduğum şey:

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

Nedense alıyorum Error: "Compare" is not a type name

Beyanı olarak değiştirme priority_queue <Node, vector<Node>, bool Compare>

bana verir Error: expected a '>'

Ben de denedim:

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

Nasıl doğru bir şekilde beyan etmeliyim priority_queue?

Yanıtlar:


114

Bir sınıf Comparetanımlamalı operator()ve bunun için şu şekilde aşırı yüklemelisiniz :

class Foo
{

};

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

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

Ya da bazı nedenlerden dolayı sınıf yapamıyorsanız, bunun std::functioniçin kullanabilirsiniz :

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
Mükemmel, tam aradığım şey. Ayrı bir ders yapmayı hiç düşünmedim. İlk örnek daha iyi bir stil olarak kabul edilir mi?
Steven Morad

2
@StevenMorad, sınıfı aşırı yüklenmiş olarak kullanmayı tercih ediyorum operator(), daha basit görünüyor.
awesoon

2
@soon Neden operatörü () aşırı yüklüyoruz? Bu, öncelikli kuyruğun dahili olarak nasıl uygulandığıyla bağlantılı mı? aşırı yükleme> veya <sezgisel olarak mantıklı, ancak () operatör çok fazla değil
Piyush

2
@Piyush, soru, özel bir karşılaştırıcıyı pritority_queue. operator<Dahili std::lesskarşılaştırıcıyı aşırı yüklemek ve kullanmak mümkündür , ancak soruya göre bool Compare(Node a, Node b)sınıfın dışında beyan edilen Node.
awesoon

3
Ben sözdizimi hatırlayamıyorum şimdi muhtemelen 50 kez gibi, bu cevaba keep coming back
Rockstar5645

52

Kabul edilen cevap, std::functionkarşılaştırıcı olarak bir sınıf veya a kullanmanız gerektiğine inanmanızı sağlar . Bu doğru değil! Cute_ptr yanıtının gösterdiği gibi, kurucuya bir işlev göstericisi geçirebilirsiniz. Ancak, bunu yapmak için sözdizimi burada gösterilenden çok daha basittir:

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

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

Yani, işlevin türünü açıkça kodlamanıza gerek yoktur, bunu sizin için derleyicinin yapmasına izin verebilirsiniz decltype.

Karşılaştırıcı bir lambda ise bu çok kullanışlıdır. Lambda türünü kullanmaktan başka bir şekilde belirleyemezsiniz decltype. Örneğin:

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

2
Bu harika, merak ediyorum burada olası tuzaklar (sorunlar) var mı? Bu cevabın daha fazla görünürlük ve tartışma aldığını görmek isterim.
Apollys,

1
@Apollys: Bu yöntemi düzenli olarak kullanıyorum (genellikle Comparebir lambda, bunun için bildirim yazmak imkansızdır), herhangi bir tuzak bilmiyorum.
Cris Luengo

Bunu bir lambda işlevi için yapacak olsaydınız, lambda işlevinin gövdesini nereye koyardınız? Bunu bir değişkende saklamak istiyorsunuz fönceden ve daha sonra değiştirmek Compareile f?
Eric Auld

@EricAuld: Evet, Compareburada olduğu gibi bir lambda işlevi olabilir auto Compare = [](){};. Ama decltype(Compare)bunun yerine kullanmanız gerekiyor decltype(&Compare).
Cris Luengo

Merhaba Chris, bu harika, öncelikli sıra için decltype ile kullanılacak bir format arıyordum ve bir sınıf bildirmeden mükemmel cevabı verdin! Teşekkürler!
Amanda Wang

17

Üçüncü şablon parametresi operator()(Node,Node)aşırı yüklenmiş bir sınıf olmalıdır . Yani şu şekilde bir sınıf oluşturmanız gerekecek:

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

Ve sonra bu sınıfı aşağıdaki gibi üçüncü şablon parametresi olarak kullanacaksınız:

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

14
Operatör yöntemi halka açık olmalıdır.
knezi

1
Üçüncü şablonun bir sınıf olması gerekmez. Bir işlevin türü olabilir.
Cris Luengo

1
Cpluplus'a göre : Bu bir işlev işaretçisi veya işlev nesnesi olabilir
Benav

10

Sorunuzu doğrudan cevaplamak:

priority_queueKullanarak bir düğüm bildirmeye çalışıyorumbool Compare(Node a, Node b) as the comparator function

Şu anda sahip olduğum şey:

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

Bazı nedenlerden dolayı Hata alıyorum:

"Compare" is not a type name

Derleyici size tam olarak neyin yanlış olduğunu söylüyor: Comparebir tür adı değil, iki alan Nodesve bir bool.
İhtiyacınız olan şey, fonksiyon işaretçisi tipini belirlemektir:
std::priority_queue<Node, std::vector<Node>, bool (*)(Node, Node)> openSet(Compare)


Bu tam olarak öncelikli sıra bildiriminde bir işlev vermek için aradığım şey, teşekkürler!
Amanda Wang

6

Bir lambda işlevi de kullanılabilir.

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

6

Önce karşılaştırmayı tanımlamalısınız. Bunu yapmanın 3 yolu vardır:

  1. sınıf kullan
  2. yapı kullanın (sınıfla aynıdır)
  3. lambda işlevini kullanın.

Sınıfı / yapıyı kullanmak kolaydır çünkü bildirmek kolaydır, sadece bu kod satırını çalıştırma kodunuzun üzerine yazı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)
   }
};

Arama kodu:

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

Noktaya kadar @shivam Mishra.
fight_club

3

Bunun herkese yardımcı olması durumunda:

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

0

struct'u tercih eder ve std :: daha büyüklerin yaptığı şeydir

struct Compare {
  bool operator()(Node const&, Node &) {}
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.