如何根据长度THEN字母顺序对数组字符串进行排序?

时间:2017-08-24 15:14:39

标签: c++ sorting

我这样做是因为我学习编程的网站,我根本无法解决这个问题。

#include <iostream>
#include <algorithm>
#include <string>
#include <vector>
using namespace std;

int main ()
{
    int n;
    string thename;
    vector <pair<string,int>> name;
    cin >> n;
    for (int i = 0; i < n; i++)
    {
        cin >> thename;
        name.push_back(make_pair(thename, thename.length()));
    }
    sort(name.begin(), name.end());
    sort(name.begin(), name.end(),
     [](const pair<string, int>& lhs, const pair<string, int>& rhs) {
             return lhs.second < rhs.second; } );
    for (int i = 0; i < n; i++)
    {
        cout << name[i].first<< endl;
    }
}

我的老人建议我不要使用lambda排序,因为我自己还是不太了解它。但我仍会接受任何lambda排序的答案。 任何人都可以帮助我吗?

3 个答案:

答案 0 :(得分:5)

问题是std::sort不稳定 - 这意味着当您按长度排序时,会按名称销毁排序。

easy 这样做的方法是扭转你的对。 std::pair有一个operator <,用于比较first个值,如果它们相同,则会比较second值。所以你需要的是:

#include <iostream>
#include <algorithm>
#include <string>
#include <vector>
using namespace std;
int main ()
{
    int n;
    vector <pair<int,string>> name;
    cin >> n;
    for (int i = 0; i < n; i++)
    {
        string thename;
        cin >> thename;
        name.push_back(make_pair(thename.length(),thename));
    }
    sort(name.begin(), name.end());
    for (const auto& n: name)
    {
        cout << n.second << endl;
    }
}

注意我已经在循环中移动thename(它永远不会在外面使用),并使最终for循环成为一个foreach循环(在可能的情况下应该是你喜欢的循环形式)。

然而您不需要将长度存储在向量中。您可以只存储名称,然后使用自定义比较器进行比较。

#include <iostream>
#include <algorithm>
#include <string>
#include <vector>
using namespace std;
int main ()
{
    int n;
    vector<string> name;
    cin >> n;
    for (int i = 0; i < n; i++)
    {
        string thename;
        cin >> thename;
        name.push_back(thename);
    }
    sort(name.begin(), name.end(),
        [](const string& lhs, const string& rhs)
        {
            return std::tie(lhs.length(),lhs) < std::tie(rhs.length(), rhs); 
        } );
    for (const auto& n : name)
    {
        cout << n << endl;
    }
}

请注意,我使用std::tie来比较长度和字符串。优于std::make_pair的优点是它将默认使用引用,因此不会复制字符串。与自己做的相比,优势在于 更容易正确(并且它也更容易阅读)。

请注意,您可以替换lambda

[](const string& lhs, const string& rhs)
{
    return std::tie(lhs.length(),lhs) < std::tie(rhs.length(), rhs); 
}
通过手动编写的仿函数

struct MyLessString
{
    bool operator () (const string& lhs, const string& rhs) const
    {
        return std::tie(lhs.length(),lhs) < std::tie(rhs.length(), rhs); 
    }
};

并使用它:

sort(name.begin(), name.end(), MyLessString{});

答案 1 :(得分:3)

您不需要vector<pair<int,string>来存储您的字符串数组,您可以vector<string>并在此处编写适当的排序函数是一个示例:

#include <iostream>
#include <algorithm>
#include <string>
#include <vector>

int main ()
{
    int n;
    std::string thename;
    std::vector <std::string> name;
    std::cin >> n;
    for (int i = 0; i < n; i++)
    {
        std::cin >> thename;
        name.push_back(thename);
    }
    sort(name.begin(), name.end(),
     [](const std::string& lhs, const std::string& rhs) {
             return lhs.size() == rhs.size() ? 
                    lhs < rhs : lhs.size() < rhs.size(); } );
    for (int i = 0; i < n; i++)
    {
        std::cout << name[i]<< std::endl;
    }
}

输入:

4
Joe
Ann
Ralph
Andrew

输出:

Ann
Joe
Ralph
Andrew

答案 2 :(得分:0)

我建议pidgeonhole排序,然后是每种pidgenhole。

初始步骤仅为O(N + n),然后在O(p log p)中对每个pidgeonhole进行排序,因为每个p&lt; = n总排序时间应小于或等于O(n log n)

警告未经测试的代码:

#include <iostream>
#include <algorithm>
#include <string>
#include <vector>
using namespace std;

constexpr const int MaxNameLength = 32; // arbitrary chosen length

int main () {
    int n;
    string thename;
    vector <vector<string>> name;
    int maxLen = MaxNameLength;
    name.resize(MaxNameLength);
    cin >> n;

    for (int i = 0; i < n; i++) {
        cin >> thename;
        if (name.length() > maxLen) {
          name.resize(thename.length()); 
          maxLen = thename.length();
        }
        name[thename.length()].emplace_back(thename);
    }

    for (auto& len: name) {
      sort(len.begin(), len.end());
    }

    for (int i = 0; i < n; i++) {
        cout << name[i].first<< endl;
    }
}