在C ++中使用比较器

时间:2014-10-21 16:26:54

标签: c++

以下是合并k排序列表的c ++代码。但我很困惑阅读前4行代码。我知道它的作用只是混淆了它是如何做到的。有人可以向我解释这些问题吗?

为什么要使用struct? “运营商”之后的“()”是什么? 为什么要使用“>”而不是“<”由于包括结果列表在内的所有列表都按升序排列?

struct compare {
    bool operator() (ListNode* &left, ListNode* &right) {
        return left->val > right->val;
    }
};

class Solution {
public:
    ListNode *mergeKLists(vector<ListNode *> &lists) {
        priority_queue<ListNode *, vector<ListNode *>, compare> heap;
        for (int i = 0; i < lists.size(); i++) {
            if (lists[i]) heap.push(lists[i]);
        }
        ListNode *dummy = new ListNode(0);
        ListNode *cur = dummy;
        while (!heap.empty()) {
            ListNode *min = heap.top();
            heap.pop();
            cur->next = min;
            cur = min;
            if (min->next) {
                heap.push(min->next);
            }
        }
        return dummy->next;
    }
};

3 个答案:

答案 0 :(得分:4)

您的struct compare就是所谓的仿函数函数对象

struct compare
{
  bool
  operator() (const ListNode& left, const ListNode& right) const
  {
    return left.val > right.val;
  }
};

void
example_usage(const ListNode& left, const ListNode& right, const compare cmp)
{
  if (cmp(left, right))
    std::cout << "left is greater" << std::endl;
  else
    std::cout << "right is greater" << std::endl;
}

(因为我使用了对指针的引用并使这些非const过多地​​打扰了我,所以我更改了签名。)

在许多情况下使用函数指针是一种方便的替代方法。最重要的是,当在模板中使用时(如在您的示例中),编译器通常能够内联对运算符()的调用。使用函数指针并不容易。

目前尚不清楚这是否与您的示例相关,但通常,仿函数的优势在于它可以在任何地方(也在函数体内)声明,而函数只能在全局范围内声明或作为类成员声明。这允许使用仿函数更好地封装。从C ++ 11开始,我们将 lambdas 作为另一种选择:

auto cmp = [](const ListNode& left, const ListNode& right)->bool{
    return left.val > right.val;
};

它可以像仿函数一样使用。 (如果你给它一个lambda表达式,编译器很可能会创建一个仿函数。)

答案 1 :(得分:1)

为什么要使用struct?

这里没有必要使用结构,虽然它没有受到伤害。

&#34;()&#34;是什么? for&#34; operator&#34;?

查找运算符重载教程。

为什么要使用&#34;&gt;&#34;而不是&#34;&lt;&#34;由于包括结果列表在内的所有列表都按升序排列?

使用&lt;&lt;比较这些,所以我不知道为什么,除了尴尬。

此外,参数应为(const ListNode* left, const ListNode* right),如果在结构内部,则成员函数也应为const。这里没有必要参考它们。我还要考虑你是否需要一个指针和动态分配的数据结构。

答案 2 :(得分:0)

为什么要使用struct?

可以是structclass。除了struct的成员之外,它们基本上是相同的。public成员默认为class,成员private为默认struct,以及2.关于人们的一般观点应该使用class用于POD(普通旧数据)和... operator()(...)用于其他所有数据。

“运营商”之后的“()”是什么?

这个很有趣。 class函数调用运算符定义了重载。每当你调用一个函数时,你肯定会使用这个运算符,将参数封装在括号中,并使返回值成为表达式的结果。

在旁注中,带有重载函数调用运算符的structfunctor通常称为<

为什么要使用“&gt;”而不是“&lt;”由于包括结果列表在内的所有列表都按升序排列?

这也是另一个有趣的问题。我们的想法是, STL(标准模板库)旨在供几乎所有使用C ++的人使用,并且旨在为执行某些操作提供便利。因此,STL中的所有工具都可以用于任何类型,包括用户定义的类型。

但是,默认情况下,用户定义的类型没有>a > b等运算符重载,因此用户必须重载它们。

b < a的结果与<基本相同。现在想象一下,如果其中一些工具使用>,而其他工具则使用>。每个人都必须使两个运营商都超负荷,即使它们只是彼此的补充,并且可以用来互相替代。

因此,设置了一个标准,以便STL仅使用{{1}}运算符,并且只要求您重载一个运算符。

在旁注中,您可以使用std::less模板化仿函数进行简单操作(如小于比较),std::function用于更复杂的操作,而不是编写自己的比较仿函数。 / p>

感谢您的阅读。