ALL, 我有以下问题。
考虑以下课程:
class A
{
public:
.....
private:
int m_a, m_b;
double m_c;
};
我有一个这类对象的矢量。
此向量在网格中呈现给用户,并且他可以单击列标题以对网格(向量)的元素进行排序。 问题来自于用户可以按住CTRL键并单击行标题,在这种情况下,网格(向量)应按2列(类的成员)排序。
我可以编写一个简单的排序器类,它将根据一个成员(列)进行排序,但我真的不明白如何选择第二个排序列并进行排序。
有人可以帮忙吗?
答案 0 :(得分:2)
执行此操作的最简单方法是依次对每列进行排序,从最低有效列开始。因此,如果用户选择按a then b then c
排序,则首先按c
排序,然后按b
排序,最后按a
排序。最后两个排序(b
和a
)必须是稳定排序(std::stable_sort
),它会保留现有的其他相等元素的排序。
另一种方法 - 使用自定义比较功能几乎肯定更快但可能不实用。但是提出自定义比较功能并不容易。在你提供的例子中,只有三个变量,那么只有六个可能的比较函数(一个用于a,b,c的每个排序 - 你可以将未指定的列放在最后)但在一般情况下你最终有太多的枚举可能性。您可以使用复杂的switch语句集合来编写通用比较器,但该比较器的开销可能不仅仅是对向量进行多次排序。
答案 1 :(得分:1)
由于您要求提供动态创建合适比较函数的代码...
免责声明:以下代码可能无法与使用稳定排序算法(如std::stable_sort
)在性能方面多次排序向量相媲美。它只应该说明一个想法。以下代码是使用C++11
功能编写的,您可能还无法使用这些功能。但是,可以使用C++03
轻松地在boost
中重写。
假设你有你的班级A
和每个成员变量的一些getter函数:
class A
{
public:
float getA() const;
int getB() const;
// and so on.
};
我们将定义返回-1
的函数,如果A
的一个实例小于另一个实例0
,如果它们相等且1
除此以外。这些功能可以更容易组合。
using comparator = std::function<int (const A&, const A&)>;
template <class T>
comparator
make_comparator( T (A::*f)() const )
{
return [f]( const A& lhs, const A& rhs ) -> int {
if( (lhs.*f)() < (rhs.*f)() )
return -1;
else if( (lhs.*f)() == (rhs.*f)() )
return 0;
else
return 1;
};
}
现在,对于每个成员函数,我们定义了comparator
:
std::vector<comparator> comparators = {
make_comperator( &A::getA ), make_comparator( &A::getB )
};
我们可以轻松组合比较器功能:
comparator
make_comparator(
const std::vector<comparator> &comparators,
std::deque<unsigned int> indices )
{
if( indices.empty() )
{
return []( const A&, const A& ) -> int { return 0; };
}
unsigned int first = indices.front();
indices.pop_front();
return [first, &comparators, indices]( const A& lhs, const A& rhs ) -> int {
int firstCompared = comparators[first]( lhs, rhs );
if( firstCompared != 0 )
{
return firstCompared;
}
else
{
return make_comparator( comparators, indices )( lhs, rhs );
}
};
}
这些函数可以转换为less
- 就像仿函数:
std::function<bool (const A&, const A&)>
to_less( std::function<int( const A&, const A& )> f )
{
return [&f]( const A& lhs, const A& rhs ) -> bool {
return f( lhs, rhs ) < 0;
};
}
排在第一列之后,而不是第二列:
std::sort( instances.begin(), instances.end(),
to_less( make_comparator( comparators, { 0, 1 } ) ) );