std::sort配合自定义比较函数可实现字典序排序,关键在于正确定义字典序并清洗输入(如去除\r\n等隐藏字符),否则会导致排序异常。

std::sort 配合自定义比较函数就能搞定
字典序排序在 C++ 里不需要手写冒泡或快排,std::sort 是首选。关键不是“怎么排序”,而是“怎么定义字典序”。对 std::string 默认就是字典序;但如果是 std::vector<:string></:string> 或自定义结构体,就得传比较函数。
常见错误是直接用 比较两个 <code>std::string 数组(比如 arr[i] ),这没问题;但若误把 <code>const char* 当成字符串比较(比如 strcmp 没用或用了 ==),结果就错——C++ 中 char* 的 比的是地址值,不是内容。
- 对
std::vector<:string></:string>:直接std::sort(v.begin(), v.end())即可 - 对
std::vector<const char></const>:必须转成std::string或用strcmp,例如:[](const char* a, const char* b) { return strcmp(a, b) - 对结构体字段(如
struct Word { std::string text; };):比较成员a.text ,别漏掉 <code>.text
处理大小写敏感问题时别硬写 tolower 循环
默认字典序区分大小写("Z" 成立),但实际需求常要忽略大小写。有人会先统一转小写再比较,这效率低且易出错(比如 UTF-8 字符)。正确做法是用 <code>std::lexicographical_compare 配合自定义谓词,或用 std::tolower 在比较时逐字符处理。
- 安全写法(ASCII 安全):
[](const std::string& a, const std::string& b) { return std::lexicographical_compare(a.begin(), a.end(), b.begin(), b.end(), [](char x, char y) { return std::tolower(x) - 避免在比较函数里调用
std::string::to_lower()—— 这会反复构造临时对象,性能差 - 如果数据含非 ASCII 字符(如中文、emoji),
std::tolower行为未定义,此时应改用 ICU 库或明确限定输入范围
std::stable_sort 在需要保序时更稳妥
当多个字符串完全相等(比如 “apple” 出现两次),你希望它们原始相对顺序不变,就得用 std::stable_sort。普通 std::sort 不保证这点,底层可能是 introsort,会打乱等价元素位置。
- 典型场景:按单词首字母分组排序后,同首字母的单词仍保持输入顺序
- 性能代价很小(
std::stable_sort平均仍是 O(N log N),只是常数略高) - 别混淆
stable和 “稳定不崩溃”——它只指等价元素的相对位置不变
从文件读入字符串再排序容易卡在换行符上
用 std::getline 读文件时,每行末尾的 \n 已被剥离,但若混用 operator>> 和 getline,可能残留 \r(Windows 文件)或空行,导致排序时 "hello\r" 排在 "hello" 前面(因为 \r ASCII 码是 13,比任意字母都小)。
- 读完每行后手动清理:
line.erase(line.find_last_not_of(" \r\n") + 1); - 或者用
std::ifstream配合std::ws跳过前导空白,再getline - 调试时打印带转义的字符串(如用
printf("%q", line.c_str())或输出 ASCII 码)能快速发现隐藏字符
字典序本身逻辑简单,真正花时间的往往是输入清洗和边界字符处理——尤其是混合平台、混合编码的文本。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











