【问题标题】:Why is Vector used as a second argument to Priority Queue?为什么向量被用作优先队列的第二个参数?
【发布时间】:2020-03-03 08:37:28
【问题描述】:

为什么当priority_queue 用于单一数据类型时,比如'int',我们这样初始化它:priority_queue<int>;但是,当它用一对初始化时,我们添加了第二个向量类型的参数priority_queue<pair<int,int>, vector<pair<int,int>>>?

另外,我注意到添加第三个参数指定排序的几种方法。

方法一 - 结构体

struct myCompare {
   bool operator()(const pair<int, int>& A, const pair<int, int>& B) {
       return A.second < B.second;
   }
};

priority_queue<pair<int, int>, vector<pair<int, int>>, myCompare> leaderBoard;

方法 2 - Lambda

auto myComp = [](const pair<int, int>& A, const pair<int, int>& B) 
              {return A.second < B.second;};

priority_queue<pair<int, int>, vector<pair<int, int>>, decltype(myComp)> leaderBoard(myComp);

我的问题

  1. 为什么priority_queue的第二个参数是vector?这是什么意思?何时需要指定第二个参数?
  2. 在方法 2 中,为什么这个 lambda 需要 decltype
  3. 在方法2中,为什么对象leaderBoard需要初始化为(myComp)
  4. 在方法 2 中,为什么不能直接将我的 lambda 指定为第三个参数?
  5. A.second &gt; B.secondA.second &lt; B.second 有什么区别?你怎么记得哪个是升序,哪个是降序?

【问题讨论】:

  • 请,每个问题只问一个问题。

标签: c++ vector lambda priority-queue decltype


【解决方案1】:

为什么当priority_queue 用于单一数据类型时,比如'int',我们这样初始化它:priority_queue&lt;int&gt; [...]?

因为std::priority_queue是一个类模板,定义如下:

template<
    class T,
    class Container = std::vector<T>,
    class Compare = std::less<typename Container::value_type>
> class priority_queue;

如您所见,您可以仅提供 T 来实例化此类,因为其余类型将被默认设置。你可以阅读更多关于template default arguments here的信息。

但是,当它用一对初始化时,我们添加第二个向量类型的参数priority_queue&lt;pair&lt;int,int&gt;, vector&lt;pair&lt;int,int&gt;&gt;&gt;?

因为有人想表达清楚。 priority_queue&lt;pair&lt;int, int&gt;&gt; 等价于priority_queue&lt;pair&lt;int,int&gt;, vector&lt;pair&lt;int,int&gt;&gt;&gt;,因为第二个模板类型 (vector&lt;pair&lt;int, int&gt;&gt;) 默认会出现。

  1. 为什么priority_queue的第二个参数是向量?这是什么意思?何时需要指定第二个参数?

我们不需要明确指定它。第二个模板参数是用于数据内部表示的类型。 std::priority_queue 是一个容器适配器,这意味着它本身并不是一个容器——它使用一些其他容器并包装它与某种实用程序。

  1. 在方法 2 中,为什么这个 lambda 需要 decltype?

因为你需要提供一个类型myComparestruct,所以它是一个类型的名称。 myComp 不是类型,而是变量。你想得到它的声明类型吗?使用decltype

  1. 方法2中,为什么需要用(myComp)初始化对象leaderBoard?

因为你不能默认构造一个给定 decltype 的 lambda (this got relaxed in C++20) 的对象。您需要使用以下构造函数:

explicit priority_queue(const Compare& compare)
    : priority_queue(compare, Container()) { }

它需要一个可调用的(在本例中为 lambda),将用作比较器。

  1. 在方法 2 中,为什么不能直接将我的 lambda 指定为第三个参数?

您的意思是作为第三个template 参数?因为到目前为止,lambdas 不能在未评估的上下文中使用,而为模板提供类型就是其中之一。

5.1。 A.second &gt; B.secondA.second &lt; B.second有什么区别?

差异非常明显。一个检查A.second 是否大于第二个参数,另一个检查是否相反。它通常用于排序(用于比较元素)。

5.2 你怎么记得哪个是升序,哪个是降序?

这很简单 - C++ 的概念是在 left 手边 参数和 right 参数之间使用 &lt; > 手边 论据,像这样:left_hand_side &lt; right_hand_side.

【讨论】:

  • 感谢您,但对于 5.2,我的意思是:如果我们有 1 2 4 1 2 51 5 3 1 2 的列表,我怎么知道 return A &lt; B 是否会将它们按升序或降序排列。据我了解,B是第二个元素,A是第一个元素,所以说B必须大于A,因此升序?
  • @TomerTzadok 正确。排序算法需要一个可调用比较器,给定两个任意元素,它将表示一个严格、弱排序,即&lt; 关系。他们根据&lt; 关系对升序进行排序。例如,降序排序只是升序排序,但使用&gt; 关系
【解决方案2】:

方法2中,为什么需要初始化对象leaderBoard 与(myComp)

这取决于您使用的 C++ 标准。在 C++20 之前,您需要将 lambda 表达式创建的函子传递给 priority_queue 构造函数,因为在 C++20 之前的 lambdas 不是默认可构造的。

从 C++20 开始,您可以编写:

priority_queue<pair<int, int>, vector<pair<int, int>>, decltype(myComp)> leaderBoard;

它会正常工作,因为编译器知道 lambda 的类型 - 由 decltype(myComp) 指定,并且它可以调用其默认 ctor。


在方法 2 中,为什么我不能将我的 lambda 指定为第三个参数 直接?

是的,你可以,但你仍然需要使用decltype 来获取比较器类型:

priority_queue<pair<int, int>, vector<pair<int, int>>, 
     decltype( [](const pair<int, int>& A, const pair<int, int>& B) 
              {return A.second < B.second;} ) > leaderBoard;

【讨论】:

  • IIRC,我们不能在未评估的上下文中使用 lambda,例如在 decltype 内部。
  • @DanielLangr 根据this paper 是允许的。我在G++下用c++2a测试了上面的代码,编译正常。
【解决方案3】:

为什么priority_queue的第二个参数是向量?

您可以使用任何满足certain requirements 的容器。 vector 是一个合理的默认选择。

这是什么意思,什么时候需要指定第二个参数?

如果你想改变它的默认值,或者你想指定第三个。 std::priority_queue&lt;std::pair&lt;int,int&gt;&gt; 是没有指定第二个参数的有效类型。

在方法 2 中,为什么这个 lambda 需要 decltype?

如果要使用自定义比较器,则必须将其类型指定为第三个模板参数。每个 lambda 都有自己独特的类型,获取它的唯一方法是通过decltype

方法2中,为什么需要用(myComp)初始化对象leaderBoard

因为基于struct 的比较器可以默认构造,但基于 lambda 的比较器不能。相关的构造函数是

priority_queue() : priority_queue(Compare(), Container()) { }
priority_queue(const Compare& compare) : priority_queue(compare, Container()) { }

如果您不提供compare,则使用Compare()myCompare() 是有效值,decltype(myComp)() 不是。

在方法2中,为什么不能直接将我的lambda指定为第三个参数?

你需要一个类型,而不是那个类型的值。

A.second > B.second 和 A.second

交换参数的顺序(或者,等效地,&lt;&gt;)将最小堆转换为最大堆,反之亦然,即该顺序决定了 .top() 将返回哪个元素,即最小或最大。

【讨论】:

  • In method 2, why can I not specify my lambda as the third argument directly? 我的意思是,为什么我不能像在任何其他 STL 算法中那样用 lambda 表达式 [](const pair&lt;int, int&gt;&amp; A, const pair&lt;int, int&gt;&amp; B) {return A.second &lt; B.second;}; 替换 decltype(myComp)?我想这是因为这是一个正在构造的对象,而不是算法。我也不明白decltype(myComp) 适合priority_queue 构造函数的位置。介意详细说明一下吗?
  • @TomerTzadok 在 C++20 之前,该语言不允许您在模板中声明 lambda。
  • @TomerTzadok, [](...) {...} 是一个值,而不是一个类型。你需要一个类型。
猜你喜欢
  • 2014-01-12
  • 2023-04-03
  • 1970-01-01
  • 2010-10-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-06-25
相关资源
最近更新 更多