字符串指针的排序向量

Sorting vector of string pointers

本文关键字:向量 排序 指针 字符串      更新时间:2023-10-16

很抱歉,如果已经在某处问过这个问题,但我无法找到我正在寻找的答案。

我有一个 std::string 指针的向量,我想按字母顺序排序,但我一直无法弄清楚如何做到这一点。我正在使用std::sort。

我编写了一个快速程序来测试我试图做什么(因为在实际实现中,我的代码是在子进程中运行的,所以很难调试):

#include <string>
#include <algorithm>
#include <vector>
#include <string.h>
bool cmpStrPtrs(std::string *a, std::string *b) {
std::string a1 = *a;
std::string a2 = *b;
if(a1 == a2) return 0;
return a1 > a2 ? 1 : -1;
}
int main(int argc, char *argv[]) {
std::vector<std::string *> vec;
std::string *str1 = new std::string("AAAAA");
std::string *str2 = new std::string("aaaaa");
std::string *str3 = new std::string("xxxxx");
std::string *str4 = new std::string("bfuen");
std::string *str5 = new std::string("xylophone");
vec.push_back(str1);
vec.push_back(str2);
vec.push_back(str3);
vec.push_back(str4);
vec.push_back(str5);
std::sort(vec.begin(), vec.end(), cmpStrPtrs);
for(std::string *str : vec) {
printf("%sn", str->c_str());
}
return 0;
}

当我运行这个时,我得到这个输出:

$ ./strsort
xylophone
bfuen
xxxxx
aaaaa
AAAAA

这似乎根本没有按字母顺序排列,所以我可以假设我要么错误地使用了 sort(),要么我的比较器函数有问题。我也在没有比较器功能的情况下尝试过,我认为这只是根据它们的内存位置从最小到最大对它们进行排序,这实际上并没有改变任何东西。我也尝试使用

bool cmpStrPtrs(std::string *a, std::string *b) {
return a->compare(*b);
}

但它给了我同样的结果。

如果相关,我将使用 c++17 标准使用 g++ 进行编译。

std::string::compare返回一个int,而不是一个bool。根据 cppreference.com 返回值为

负值,如果 *这出现在参数指定的字符序列之前,按字典顺序排列

如果两个字符序列比较等效,则为零

正值,如果 *这出现在参数指定的字符序列之后,按字典顺序排列强文本

返回值将强制转换为bool对于所有非零值,其计算结果为true。这意味着您的函数为每对不相同的字符串返回true

C++ 标准实际上定义了字符串的operator<,因此您可以将函数更改为

bool cmpStrPtrs(std::string *a, std::string *b) {
return *a < *b;
}

但这仍然会在您的代码中留下一个大问题。您绝对不需要指针。事实上,你现在正在泄漏记忆,因为你忽略了delete它们。这项工作的正确工具是std::vector<std::string>.这还有一个额外的好处,即如果没有额外的间接寻址级别,std::sort可以在没有帮助程序函数的情况下隐式调用operator<,从而导致以下解决方案。

std::vector<std::string> vec;
vec.emplace_back("AAAAA");
vec.emplace_back("aaaaa");
vec.emplace_back("xxxxx");
vec.emplace_back("bfuen");
vec.emplace_back("xylophone");
std::sort(vec.begin(), vec.end());

你可以用lambda来做到这一点:

std::sort(vec.begin(), vec.end(), [](std::string * a, std::string * b) {
return *a < *b;    
});

您的比较函数旨在模拟小于运算符 - 这意味着如果 a 在 b 之前,它应该返回 true。如果 a 不等于 b,则当前实现返回 true。

你有:

if(a1 == a2) return 0;
return a1 > a2 ? 1 : -1;

应该是:

if(a1 == a2) return false;
return a1 > a2 ? false : true;

或只是:

return a1 < a2;

std::sort期望严格弱排序。它不会给平等的废话;它只关心前后。

如果右侧先于左侧,则比较函数应返回 true。不幸的是,在

bool cmpStrPtrs(std::string *a, std::string *b) {
std::string a1 = *a;
std::string a2 = *b;
if(a1 == a2) return 0;
return a1 > a2 ? 1 : -1;
}

对于任何非 0 的值,bool都是正确的。这意味着大于和小于都是真的。这使得逻辑排序几乎是不可能的,因为大于和小于之前。

改进切口 1:根据词典(字母顺序)排序返回bool。字符串已经实现了一个小于运算符,它完全可以执行您想要的操作。让我们使用它。

bool cmpStrPtrs(std::string *a, std::string *b) {
std::string a1 = *a;
std::string a2 = *b;
return a1 < a2;
}

改进剪辑 2:std::string a1 = *a;创建一个全新的字符串,该字符串是原始字符串的副本。由于您有一个指向原始指针的指针,因此您可以取消引用该指针并使用原始指针。不需要副本。

bool cmpStrPtrs(std::string *a, std::string *b) {
return *a < *b;
}