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

How do I sort string of arrays based on length THEN Alphabetic order?

本文关键字:字符串 数组 排序 顺序 何根 然后      更新时间:2023-10-16

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

#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 排序答案。 谁能帮我?

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

要做到这一点,最简单的方法是反转你的配对。std::pair有一个比较first值的operator <,如果它们相同,则比较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{});

你不需要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

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

第一步只有 O(N+n(,然后对 O( p log p 中的每个鸽子洞进行排序,因为每个 p <= 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;
}
}