基于C ++中动态生成的数字对列表进行排序

时间:2010-06-15 13:58:26

标签: c++ sorting

我有一个对象列表(在这种情况下为“Move”)我想根据他们的计算评估进行排序。所以,我有List和一堆与列表中的元素“关联”的数字。我现在想要使用具有最低关联数字的第一个元素和具有最高关联数字的最后一个元素对List元素进行排序。一旦物品订购,我可以丢弃相关的号码。我该怎么做?

这就是我的代码(亲切):

list<Move> moves = board.getLegalMoves(board.turn);

for(i = moves.begin(); i != moves.end(); ++i)
{
    //...
    a = max; // <-- number associated with current Move
}

3 个答案:

答案 0 :(得分:10)

我建议Schwartzian transform排序。创建一个新的向量(我推荐用于更有效排序的向量)的关联值对,以及指向其项的指针。对对矢量进行排序,然后从排序后的矢量中重新生成列表。由于operator<std::pair上定义为要通过该对中的第一项进行比较,然后是第二项,您将获得正确的排序。

示例:

#include <algorithm> // gives you std::sort
#include <utility>   // gives you std::pair

typedef double CostType;
typedef std::pair<CostType, Move*> Pair;

// Create the vector of pairs
std::vector<Pair> tempVec;
tempVec.reserve(moves.size());
for (std::list<Move>::iterator i = moves.begin(); i != moves.end(); ++i)
{
    CostType cost   = calcCost(*i);
    Move*    ptrToI = &(*i);
    tempVec.push_back(Pair(cost, ptrToI));
}

// Now sort 'em
std::sort(tempVec.begin(), tempVec.end());

// Regenerate your original list in sorted order by copying the original
// elements from their pointers in the Pair.
std::list<Move> sortedMoves;
for (std::vector<Pair>::iterator i = tempVec.begin(); i != tempVec.end(); ++i)
{
    sortedMoves.push_back(*(i->second));
}

请注意,您需要我假设的calcCost函数。如果比较值计算耗时,则此方法优于创建比较函数。这样,您只需支付计算比较N次的成本,而不是2 * N * log(N)。

答案 1 :(得分:4)

您可以制作一个比较函数,以您希望的方式比较这两个元素。

bool compare_m (const Move &first,const Move &second)
{
  if (first.thing_you_are_comparing_on() < second.thing_you_are_comparing_on()) return true;
  else return false;
}

其中“thing_you_are_comparing_on”是Move类的某个成员,它为您提供所需的顺序。我们在这里使用const来确保我们只是比较而不是实际更改比较函数中的对象。然后,您可以使用compare_m作为比较函数调用列表中的sort方法:

moves.sort(compare_m)

需要注意的是,如果比较函数的计算特别昂贵,那么在排序之前预先计算所有相关的排名数值可能是值得的。

这需要在move类中添加一些东西来存储等级以供以后使用:

class Move{
    //rest of move class

    public:
    int rank;
};

list<Move>::iterator iter;

for(iter = moves.begin(); iter != moves.end(); ++iter)
{
    //...
    (*iter).rank = max; // store the number associated with current Move
}

bool compare_rank (const Move &first,const Move &second)
{
  if (first.rank < second.rank) return true;
  else return false;
}

答案 2 :(得分:0)

std::sort用于对STL集合进行排序。如果您正在排序的集合中的元素可以通过调用operator<进行比较,并且有问题的集合是vector,那么排序非常简单:

std::sort(collection.begin(), collection.end());

如果相关集合不是vector而是list,那么您就不能使用std::sort的常规版本,但可以使用{{ 3}}的版本代替:

list<int> numbers;
numbers.sort();

STL的sort以及STL中的大多数其他算法有两种形式。一个是我们已经看到的简单版本,它只使用operator<来比较两个元素。另一个是“谓词”版本,而不是使用operator<使用您提供的比较std::list。这是您需要在您的情况下使用的。 sortlist的谓词版本,这是您需要在您的案例中使用的版本。

您可以通过多种方式创建一个仿函数,但其​​中一个最有用的方法是从std::unary_functionfunctor派生一个类,具体取决于您的仿函数将采用多少参数 - 在你的情况下,两个。覆盖函数调用运算符std::binary_function并添加比较两个元素的代码:

class compare_functor : public std::binary_function<Move, Move, bool>
{
public:
  bool operator(const Move& lhs, const Move& rhs) const
  {
    int left_val = lhs.Value();
    int right_val = rhs.Value();
    return left_val < right_val;
};

这是一个完整的工作示例,将所有内容放在一起。在这个程序中,我有一个10 Move的列表,而不是string的列表。每个string是6个随机字符。该列表由对operator()的调用填充,generate_n使用仿函数generator创建每个随机字符串。然后我通过调用copy并传递一个将值转储到stdout(ostream_iterator)的输出迭代器来转储该字符串列表及其值。每个字符串的值只是每个字符的数值之和,由函数strng_val计算。

然后我使用list的谓词版sort对列表进行排序。 sort使用的比较谓词为evaluator。然后我最终将结果列表和字符串值再次转储到屏幕上,如上所示:

#include <cstdlib>
#include <iostream>
#include <list>
#include <string>
#include <algorithm>
#include <ctime>
#include <sstream>

using namespace std;

class generator 
{
public:
    generator() { srand((unsigned)time(0)); }
    string operator()() const 
    {
        string ret;
        for( int i = 0; i < 6; ++i )
            ret += static_cast<char>((rand()/(RAND_MAX/26)) + 'A');
        return ret;
    }
};

unsigned string_val(const string& rhs)
{
        unsigned val = 0;
        for( string::const_iterator it = rhs.begin(); it != rhs.end(); ++it )
            val += (*it)-'A'+1;
        return val;
};

class evaluator : public std::binary_function<string,string,bool>
{
public:
    bool operator()(const string& lhs, const string& rhs) const
    {
        return string_val(lhs) < string_val(rhs);
    }
};

class string_dumper : public std::unary_function<string, string>
{
public:
    string operator()(const string& rhs) const
    {
        stringstream ss;
        ss << rhs << " = " << string_val(rhs);
        return ss.str();
    }
};

int main() 
{
    // fill a list with strings of 6 random characters
    list<string> strings;
    generate_n(back_inserter(strings), 10, generator());
    // dump it to the screen
    cout << "Unsorted List:\n";
    transform(strings.begin(), strings.end(), ostream_iterator<string>(cout, "\n"), string_dumper());

    // sort the strings according to their numeric values computed by 'evaluator'
    strings.sort(evaluator());  // because this is a 'list', we are using list's 'sort'
    // dump it to the screen
    cout << "\n\nSorted List:\n";
    transform(strings.begin(), strings.end(), ostream_iterator<string>(cout, "\n"), string_dumper());
    return 0;

}