1

全部,我有以下问题。

考虑以下课程:

class A
{
public:
.....
private:
    int m_a, m_b;
    double m_c;
};

我有一个此类对象的向量。

该向量在网格中呈现给用户,并且(s)他可以单击列标题以对网格(向量)的元素进行排序。问题来自这样一个事实,即用户可以按住 CTRL 键并单击行标题,在这种情况下,网格(向量)应按 2 列(类的成员)排序。

我可以编写一个简单的排序器类,它将基于一个成员(列)进行排序,但我真的不明白如何选择第二个排序列并进行排序。

有人可以帮忙吗?

4

2 回答 2

2

最简单的方法是依次按每列排序,从最不重要的列开始。因此,如果用户选择排序依据a then b then c,那么您首先排序依据c,然后排序依据b,最后排序依据a。最后两个排序 (ba) 必须是稳定排序( std::stable_sort),它保留其他相等元素的现有顺序。

另一种方法——几乎可以肯定更快但可能不实用——是使用自定义比较函数。但是想出自定义比较功能并不容易。在您提供的示例中,只有三个变量,那么只有六个可能的比较函数(一个用于 a、b、c 的每个排序 - 您可以将未指定的列放在最后)但在一般情况下,您最终有太多的可能性无法列举。您可以使用复杂的 switch 语句集合来编写通用比较器,但该比较器的开销很可能会超过对向量进行多次排序。

于 2013-11-04T06:52:22.933 回答
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-like 仿函数:

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 } ) ) );
于 2013-11-04T09:33:28.783 回答