将对象传递给compare函数会使排序变慢
Passing object to compare function makes sorting slow?
我的程序中有以下代码。
//Compare class
class SortByFutureVolume
{
public:
SortByFutureVolume(const Graph& _g): g(_g){}
bool operator() (const Index& lhs, const Index& rhs){
return g.getNode(lhs).futureVolume() > g.getNode(rhs).futureVolume();
}
private:
Graph g;
};
然后我用它进行排序,如下所示:
std::sort(nodes.begin(), nodes.end(),SortByFutureVolume(g));
当我在mac电脑上对大小为23K的矢量运行上述代码时,它只需几秒钟就完成了。然而,当我在我的ubuntu 14机器上运行时。这需要几分钟的时间,甚至还没有完成。
我搜索了这个问题,在这里找到了以下解决方案。我可以防止std::sort复制传递的比较对象吗
基本上修改我的代码,这样可以修复问题:
SortByFutureVolume s(g);
std::sort(_nodes.begin(), _nodes.begin()+ end, std::ref(s));
在这之后,我的mac和ubuntu上的运行时间是相当的。速度快多了。
我知道这是有效的,但我想明白为什么?我知道上面的代码很慢是因为复制了图和SortByFutureVolume。为什么需要std::ref()?这个解决方案是正确的吗?有更好的方法吗?
如果g
可以是只读的,则应该有Graph &
或const Graph &
,而不是在SortByFutureVolume
中有Graph
数据成员。这样,无论何时复制SortByFutureVolume
,都不会复制Graph
。
class SortByFutureVolume
{
public:
SortByFutureVolume(const Graph& _g): g(_g){}
bool operator() (const Index& lhs, const Index& rhs){
return g.getNode(lhs).futureVolume() > g.getNode(rhs).futureVolume();
}
private:
Graph& g;
// or
const Graph& g;
};
正如Benjamin Lindley在评论中指出的那样,如果将SortByFutureVolume
更改为存储指向Graph
的指针而不是引用,则SortByFutureVolume
将变为可复制分配,因为可以分配指针,但不能分配引用。那会给你
class SortByFutureVolume
{
public:
SortByFutureVolume(const Graph& _g): g(&_g){}
bool operator() (const Index& lhs, const Index& rhs){
return g->getNode(lhs).futureVolume() > g->getNode(rhs).futureVolume();
}
private:
const Graph * g;
};
另一方面,在函数参数中使用_g
作为变量名是可以的,因为它不以大写字母开头,但不使用前导下划线是一个好习惯。在全局空间中,_g
将是一个无效的标识符,因为它是为实现保留的。
std::ref
是一个伪装的指针。代码所做的是,它不是复制一个重SortByFutureVolume
对象,而是围绕指向同一对象的指针进行复制——这显然要快得多。
选项是使Graph g
成为分类器对象内部的(常量)引用。
每次复制SortByFutureVolume
时,它都会复制整个图,std::sort会根据比较函数对象的值进行大量复制。
请参阅此处:
http://coliru.stacked-crooked.com/a/49b9cdad8eb3bc06
对于简单的CCD_ 17排序,它在内部对CCD_。您的图形可能被复制了相同的次数。
std::ref
只复制对比较函数对象的引用——这会删除所有深层复制,从而加快整个过程。
您正在调用的std::sort变体的原型是
template< class RandomIt, class Compare >
void sort( RandomIt first, RandomIt last, Compare comp );
(参见http://en.cppreference.com/w/cpp/algorithm/sort)
因此,编译器推断,当您传递一个不合格的SortByFutureVolume(g)
时,您传递的是值。用SortByFutureVolume
的定义构造临时需要图形的深度副本。然后可能会有第二个副本,因为临时值是通过值传递的。如果此参数是按排序中的值传递的,则将进行进一步的复制。
当您使用std::ref()
时,编译器可以推断出第三个参数是引用,因此该过程变为通过引用,从而消除了图的二次副本。
正如其他人所指出的,解决方案是将成员g
作为引用,并通过引用使构造函数接受。
class SortByFutureVolume {
const Graph& g;
public:
SortByFutureVolume(const Graph& g_) : g(g_) {}
bool operator() (const Index& lhs, const Index& rhs){
return g.getNode(lhs).futureVolume() > g.getNode(rhs).futureVolume();
}
};
当然,如果您有一个兼容C++11的编译器,您可以只使用lambda:
std::sort(nodes.begin(), nodes.end(), [&g](const Index& lhs, const Index& rhs) {
return g.getNode(lhs).futureVolume() > g.getNode(rhs).futureVolume();
});
- 如何计算此排序函数的时间复杂度?
- 什么是自定义比较器以及如何在 C++ 的排序函数中使用它?
- 自定义排序函数中的堆溢出
- 分段 排序函数实现中的错误
- 使用排序函数 c++ 对字符数组进行排序
- 类中的排序函数
- 数组为此合并排序函数提供了正确的输出,但向量给出了不正确的输出.出了什么问题?
- 快速排序函数在快速排序算法中如何工作?
- 解释标准库排序函数C++的比较谓词的工作原理?
- C++ wrt 字符串中的 STL 排序函数
- 排序函数和优先级队列 C++ 中的比较器
- 为什么当我们使用等于'='符号比较器函数时,c ++的内置排序函数不起作用?
- C++排序函数中的奇怪之处
- C++ 排序函数中的数组项赋值
- 瓶颈 C++ 排序函数Wi-Fi 信号
- 算法中的排序函数返回错误
- 排序函数如何在整数对的向量上工作?
- 从递归向后选择排序函数调用 max 和交换函数
- 排序函数未正确返回数组
- 如何将比较器添加到自定义排序函数