C++ 为什么是c++;使用自定义比较函子时,stl优先级_队列的执行效率不如预期
当我使用定制的比较函数类创建stl优先级_队列时,我发现它的性能非常差(推送元素的复杂性似乎是O(n)而不是O(logN))。但我测试使用具有相同比较函数的stl集,该集的运行速度比优先级队列快得多。为什么会这样C++ 为什么是c++;使用自定义比较函子时,stl优先级_队列的执行效率不如预期,c++,stl,set,priority-queue,C++,Stl,Set,Priority Queue,当我使用定制的比较函数类创建stl优先级_队列时,我发现它的性能非常差(推送元素的复杂性似乎是O(n)而不是O(logN))。但我测试使用具有相同比较函数的stl集,该集的运行速度比优先级队列快得多。为什么会这样 //There are a lot of horizontal lines on x-axis. Each line is represeted by a pair<int,int> p, //where p.first is the left point
//There are a lot of horizontal lines on x-axis. Each line is represeted by a pair<int,int> p,
//where p.first is the left point and p.second is the right point.
//For example, p(3,6) is a line with end points of 3 and 6.
//a vector<pair<int,int>> lines represents all these lines.
//
//I would like to scan all the end points from left to right alone x-axis.
//I choose to use a struct end_point to represent each end point,
// struct end_point{
// int x_coor; //the x coordinate of the end point;
// int index; //the index of the line, this end point belongs to, in vector lines.
// };
//For example, if there are 3 lines on x-axis line1(1,10), line2(2,9) and line3(3,8),
//the vector of lines looks like vector<pair<int,int>> lines = [(1,10), (2,9), (3,8)];
//And the 6 end points look like {1,0}, {10,0}, {2,1}, {9,1}, {3,2}, {8,2}
//I want to sort these end points by comparing their x_coor(if equal, use index to identify different lines).
//If I choose a priority_queue to sort them, it has a very poor performace(6000 μs to complete 1000 lines).
//But I do the same thing(by using the same customized compare function class) on a set,
//it runs much faster(just 246 μs) than priority_queue.
//
//My question:
//1.Why priority_queue perform so bad as to set in this example?
//2.For the comparator function class, I introduce a variable count to record how many times the compare function is called totally.
//but for priority_queue, it seems that each compare function would resume it to 0 without keeping it, while for the set, it could
//increase all the time as I expect. Is there any bug in my code(or that is the reason why there performed so differently)?
//
#include <iostream>
#include <queue>
#include <set>
#include <chrono>
using namespace std::chrono;
//generate 1000 lines of [(0, 10000), (1, 9999), (2,9998),(3,9997).....(999, 9001)]
std::vector<std::pair<int,int>> linesGenerator(){
std::vector<std::pair<int,int>> lines;
int lines_num = 1000;
int length_range = 10000;
for(int i = 0; i < lines_num; i++){
int start = i;
int end = length_range - i;
lines.push_back(std::make_pair(start, end));
}
return lines;
}
struct end_point{
int x_coor; //the x coordinate of the end point;
int index; //the index of the line, this end point belongs to, in vector lines.
end_point(int x, int i):x_coor(x), index(i){}
};
//customized compare function class for priority_queue
class pqCompare{
public:
//construct by keeping its own copy of lines.
pqCompare(std::vector<std::pair<int,int>> &_lines){
lines = _lines;
count = 0; //use for count how many times the compare operation is called.
}
bool operator()(end_point ep1, end_point ep2){
++count; //increase by 1 if this function is called once.
//std::cout<<"count:"<<count<<std::endl;
if(ep1.x_coor != ep2.x_coor){
return ep2.x_coor < ep1.x_coor;
}
return ep1.index > ep2.index;
}
private:
std::vector<std::pair<int,int>> lines;
int count;
};
//customized compare function for set, almost same as priority_queue,
//the difference is only because piroity_queue is a max_heap.
class setCompare{
public:
setCompare(std::vector<std::pair<int,int>> &_lines){
lines = _lines;
count = 0;
}
bool operator()(end_point ep1, end_point ep2){
++count;
//std::cout<<"count:"<<count<<std::endl;
if(ep1.x_coor != ep2.x_coor){
return ep1.x_coor < ep2.x_coor;
}
return ep1.index < ep2.index;
}
private:
std::vector<std::pair<int,int>> lines;
int count;
};
void test_pqueue()
{
//generate 1000 lines;
std::vector<std::pair<int,int>> lines = linesGenerator();
//create a priority_queue with cmp as comparator.
pqCompare cmp(lines);
std::priority_queue<end_point, std::vector<end_point>, pqCompare> ct(cmp);
auto tp0 = steady_clock::now();
for (int i = 0; i < lines.size(); ++i){
//for each line, there are 2 end points.
int left_point = lines[i].first;
int right_point = lines[i].second;
ct.push(end_point(left_point, i));
ct.push(end_point(right_point, i));
}
//std::cout<<"total count"<<cmp.getCount()<<"\n";
auto tp1 = steady_clock::now();
std::cout << __PRETTY_FUNCTION__ << ':' << duration_cast<microseconds>(tp1-tp0).count() << " μs\n";
}
void test_set()
{
std::vector<std::pair<int,int>> lines = linesGenerator();
setCompare cmp(lines);
std::set<end_point, setCompare> ct(cmp);
auto tp0 = steady_clock::now();
for (int i = 0; i < lines.size(); ++i){
int left_point = lines[i].first;
int right_point = lines[i].second;
ct.insert(end_point(left_point, i));
ct.insert(end_point(right_point, i));
}
auto tp1 = steady_clock::now();
std::cout << __PRETTY_FUNCTION__ << ':' << duration_cast<microseconds>(tp1-tp0).count() << " μs\n";
}
int main()
{
test_pqueue();
test_set();
}
//x轴上有很多水平线。每条线由一对p表示,
//其中p.first是左点,p.second是右点。
//例如,p(3,6)是端点为3和6的直线。
//矢量线表示所有这些线。
//
//我想从左到右扫描x轴上的所有端点。
//我选择使用结构端点来表示每个端点,
//结构端点{
//int x_coor;//端点的x坐标;
//int index;//此端点所属直线的索引,以矢量线表示。
// };
//例如,如果x轴上有3条线,即线1(1,10)、线2(2,9)和线3(3,8),
//线的向量看起来像向量线=[(1,10),(2,9),(3,8)];
//6个端点看起来像{1,0},{10,0},{2,1},{9,1},{3,2},{8,2}
//我想通过比较它们的x_coor对这些端点进行排序(如果相等,则使用索引来标识不同的线)。
//如果我选择一个优先级队列对它们进行排序,它的性能非常差(6000μs完成1000行)。
//但是我在一个集合上做同样的事情(通过使用相同的定制比较函数类),
//它的运行速度比优先级队列快得多(仅246μs)。
//
//我的问题:
//1.为什么优先级队列的性能如此糟糕,以至于在本例中设置了优先级?
//2.对于comparator函数类,我引入了一个变量计数来记录compare函数总共被调用了多少次。
//但对于priority_队列,似乎每个compare函数都会将其恢复为0,而不会保留它,而对于set,它可以
//如我所料,一直在增加。我的代码中是否存在任何bug(或者这就是为什么它们的执行方式如此不同的原因)?
//
#包括
#包括
#包括
#包括
使用名称空间std::chrono;
//生成1000行[(0,10000),(1,9999),(29998),(39997)…(999,9001)]
std::vector linesGenerator(){
std::矢量线;
int line_num=1000;
整数长度_范围=10000;
对于(int i=0;i //std::coutFyifor(int i=0;i<10000,i++)
不是有效的for循环。也许可以发布一个真实的最小、完整、可验证的示例来重现您的问题。我不确定您使用什么来比较您的运行时,但优先级队列应该仅在缓存管理方面获胜。请用一个完整的示例来更新您的问题,如生成结果的链接示例,我包括你用来衡量结论的任何机制和方法。我为我的问题提供了一个例子。我认为现在应该更清楚了。你能帮我吗?为什么你需要在比较运算符中使用一份行
?你没有使用它。如果你需要在比较运算符中使用大量数据,请保留一个ref引用它。比较运算符不应该是重量级的。在两个比较运算符中都将其更改为const reference可以解决性能问题。void test_pqueue():37μs;void test_set():384μs
1。在本例中,不需要有行的副本。可能我过于简化了它。事实上,每行还有另一个信息(例如权重值),这就是为什么我希望在compare类中保留行。