std sort似乎永远循环

时间:2013-01-20 15:00:14

标签: c++ sorting std

现在我有一个类进行二分查找。该类接受一个向量,但后来我告诉该类进行排序。

我需要能够只通过名字的潜在或姓氏进行排序,所以我将一个字符参数设置为该类中的一个选项来改变我对矢量的排序方式。我也在那个类中创建了一个operator()函数来使用* this,作为一个类向量来对向量进行排序。但它似乎只是永远循环。谁能告诉我为什么?代码如下。

*注意是否有一些我不遵循的一般做法随时通知我。我现在不想开始养成坏习惯。

按要求:Getname

void personType::getName(string& first, string& last)
{
    // get the name and set it
    first = firstName;
    last = lastName;
}


bool sBinary::operator()(studentType student1, studentType student2){
    string toCheck1, toCheck2, fName1,lName1 ,fName2 , lName2;
    student1.getName(fName1, lName1);
    student2.getName(fName2, lName2);
    toCheck1=checkStr(fName1, lName1);
    toCheck2=checkStr(fName2,lName2);
    return toCheck1<toCheck2;
}

string sBinary::checkStr(string fName, string lName){
    string toCheck;
    switch (choice){
    case 'f':
    case 'F':
        toCheck=fName;
        break;
    case 'l':
    case 'L':
        toCheck=lName;
        break;
    case 'r':
    case 'R':
        toCheck=fName+lName;
        break;
    default:
        toCheck=lName+fName;

    }

    return toCheck;

}


sBinary::sBinary(vector<studentType> _sList, char _choice){
    sList=_sList;
    steps=0;
    choice=_choice;
    sort(sList.begin(),sList.end(), *this);
}

2 个答案:

答案 0 :(得分:6)

所以,似乎不是永远不会循环,而是执行太久。这是完全不同的故事。 你的代码中有几个悲观: 主要关注的是您将*this传递给排序算法:

sort(sList.begin(),sList.end(), *this);

std::sort按值计算比较谓词,并将其复制多次。如果你定义了复制构造函数,你可以看到它:

sBinary(const sBinary& r):choice(r.choice), sList(r.sList)
{
    std::cout << "copied\n";
}

您的矢量会随着对象本身一起被复制。

例如,如果数组大小为200,则std::sort将对象 13646次复制。这意味着, 2700000 学生复制操作涉及到。

因此,您不应将*this传递给std::sort。您最好定义静态函数lessThen而不是operator(),并将其传递给排序算法。

进一步改进:

  1. Pass by reference,而不是价值。例如,在您的lessThen函数声明中应该看起来像

    static bool lessThen(const studentType& student1, const studentType& student2);
                       //^^^^^            ^
                       //constant         reference
    
  2. 重构您的studentType课程。

    你最好有两个独立的函数,返回名字和姓氏(通过常量引用)。在这种情况下,您可以摆脱将名称复制到临时变量。请注意,当您具有单个功能时,您必须复制名字和姓氏,即使永远不会使用一个名称:

    const std::string& first_name() const { return _fname; }
    const std::string& last_name() const { return _lname; }
    

答案 1 :(得分:3)

我之所以包含这一点,只是因为您应该知道如何对此列表进行排序。 Lol4t0已经谈到了使用比较器复制起来很昂贵的可怕性(而且你很难比原来的实现更昂贵)。

std::sort算法作为简单的比较器给出时,struct cmpObjects { bool operator ()(const Object& left, const Object& right) const { return (left compared to right somehow); } } 算法效果最好,并且尽可能多地内联它的实现。理想情况下,您可以实现这样的比较器运算符函数:

int

首先注意const引用的使用。您应该考虑不执行此操作的唯一时间是您的基础数据是本机内在类型(例如charstd::sort等)。在这些情况下,它实际上是更快来传递值。但在这种情况下,您的学生记录通过引用访问(无需复制)的效率最高。

关于您的具体任务,基于您的排序标准是基于选择的事实,您的任务会更复杂一些。如果您想要最大化排序速度,理想情况下,每个选择案例都有一个单一,紧凑,便宜的可复制比较器。然后,根据该选择使用适当的比较器,在调用// compares last name struct cmp_LName { bool operator ()(const studentType& left, const studentType& right) const { return left.lastName < right.lastName; } } 之前确定

例如,如果您知道要按姓氏排序,那么:

// compares first name, then last name only if first name is identical.
struct cmp_FNameLName
{
    bool operator ()(const studentType& left, const studentType& right) const
    {
        int res = left.firstName.compare(right.firstName);
        return res < 0 || (res == 0 && left.lastName < right.lastName);
    }
}

或者可能是名字,姓氏如:

sBinary

这使您对sBinary(const std::vector<studentType>& sList_, char choice) : sList(sList_) { switch (choice) { case 'L': case 'l': std::sort(sList.begin(), sList.end(), cmp_LName()); break; case 'R': case 'r': std::sort(sList.begin(), sList.end(), cmp_FNameLName()); break; .... } } 构造函数的部分看法如下所示:

std::sort

首先请注意,我们正在选择我们选择之前的实际调用const的比较技术。当我们这样做时,我们清楚地定义了我们正在使用的自定义比较器中的标准究竟是什么,以及管理它的零开销。

那么权衡呢?您需要四个比较器(cmp_LName,cmp_FName,cmp_FNameLName和cmp_LNameFName),根据您的传入选项触发要使用的比较器。但是,这样做的好处不容小觑:这将是根据选择对列表进行排序的最快方法。


附录:单一比较器

如果你对使用单个比较器的想法完全正面结合,那么尽可能便宜地复制它,并将其中排序条件中的选择埋没为sBinary以给编译器清理代码的最佳机会。我已经在下方class sBinary { // compare student based on fixed choice determine at construction. struct cmp_student { const char choice; cmp_student(char choice) : choice(choice) {}; bool operator()(const studentType& left, const studentType& right) const { switch (choice) { case 'F': case 'f': return left.firstName < right.firstName; case 'L': case 'l': return left.lastName < right.lastName; case 'R': case 'r': { int res = left.firstName.compare(right.firstName); return res < 0 || (res == 0 && left.lastName < right.lastName); } default: { int res = left.lastName.compare(right.lastName); return res < 0 || (res == 0 && left.firstName < right.firstName); } } } }; public: sBinary(const std::vector<studentType>& sList, char choice) : sList(sList) { std::sort(sList.begin(), sList.end(), cmp_student(choice)); } std::vector<studentType> sList; }; 进行了全面扩展,以展示如何做到这一点,但我强调,如果速度是您的首要考虑因素,那么最佳。

{{1}}