繁体   English   中英

标准排序似乎永远循环

[英]std sort seems to be looping forever

现在,我有一个可以进行二进制搜索的类。 该类接受一个向量,但随后我告诉该类进行排序。

我需要能够仅按名字或姓氏对它进行排序,因此我将一个字符参数设置为该类中的选择,以更改对向量进行排序的方式。 我还在该类中使一个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);
}

因此,似乎不是永远循环,而是执行时间太长。 这是完全不同的故事。 您的代码中有一些悲观:主要关注点是您将*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. 通过引用传递 ,而不是通过值传递 例如,在您的lessThen函数声明中,

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

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

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

我之所以将其包括在内,是因为您应该了解如何对列表进行排序。 Lol4t0已经讨论过拥有比较器(复制比较昂贵)的丑陋性(并且很难拥有比原始实现昂贵的比较器)。

当给定尽可能简单的比较器时, std::sort算法最有效,并且有尽可能多的机会内联其实现。 理想情况下,您可以实现这样的比较器运算符功能:

struct cmpObjects
{
    bool operator ()(const Object& left, const Object& right) const
    {
        return (left compared to right somehow);
    }
}

首先请注意const引用的使用。 唯一不考虑这样做的时间是,如果基础数据是本机固有类型(例如intchar等)。 在这些情况下,按值传递实际上更快 但是在这种情况下,可以肯定的是,您的学生记录可以更高效地通过引用进行访问(无复制)。

关于您的特定任务,由于您的排序标准是基于选择的,因此您的任务要复杂一些。 如果要最大程度地提高分类速度,则理想情况下,针对每种选择情况,都应使用一个紧凑的可廉价复制的比较器。 然后,根据该选择使用适当的比较器,该选择器调用std::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 之前选择要选择的比较技术。 当我们这样做时,我们就可以清楚地确定该标准到底在我们所使用的自定义比较器中是什么,并对其进行零开销管理。

那有什么折衷呢? 您将需要四个比较器(cmp_LName,cmp_FName,cmp_FNameLName和cmp_LNameFName),根据传入选择触发使用哪个比较器。 但是,这样做的好处不能被夸大: 这将是根据选择对列表进行排序的最快方法。


附录: 单个比较器

如果您绝对赞成使用单个比较器的想法,那么请使其尽可能便宜地进行复制,并将在排序条件下所做的选择隐藏为const以使编译器有最大的机会清理代码。 我在下面包括了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;
};

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM