std::sort 默认按字典序排序 std::string 容器,因 std::string 重载了小于运算符,直接调用即可实现字典序排列。

std::sort 默认就能按字典序排字符串
只要容器里存的是 std::string,用 std::sort 直接排序就是字典序——因为 std::string 重载了 运算符,其行为就是逐字符比较 ASCII 值(即标准字典序)。
常见错误是手动写比较逻辑,或者误以为要传自定义 comparator 才能“字典排序”,其实完全不需要。
- 对
std::vector<:string></:string>排序:std::vector<std::string> v = {"banana", "apple", "cherry"}; std::sort(v.begin(), v.end()); // 结果:{"apple", "banana", "cherry"} - 对 C 风格字符串数组(
char*)不能直接用std::sort,会按指针值排,不是字典序;必须传 comparator,比如std::strcmp: const char* arr[] = {"banana", "apple", "cherry"}; std::sort(arr, arr + 3, [](const char* a, const char* b) { return std::strcmp(a, b) < 0; });
大小写敏感是默认行为,不等于“错”
字典序严格区分大小写:"Zoo" "apple",因为 'Z'(ASCII 90)'a'(ASCII 97)。这不是 bug,是标准定义。
如果业务需要忽略大小写排序,必须显式处理,但要注意:不能简单用 std::tolower 对每个字符转小写再比——它依赖 locale,且对非 ASCII 字符(如中文、带重音字母)可能出错。
立即学习“C++免费学习笔记(深入)”;
- 安全做法是用
std::locale和std::toupper配合: std::locale loc(""); auto cmp_nocase = [&loc](const std::string& a, const std::string& b) { return std::lexicographical_compare( a.begin(), a.end(), b.begin(), b.end(), [&loc](char x, char y) { return std::toupper(x, loc) < std::toupper(y, loc); } ); }; std::sort(v.begin(), v.end(), cmp_nocase);- 更轻量的替代:只处理 ASCII,手动转小写(仅限英文场景):
[](const std::string& a, const std::string& b) { std::string la = a, lb = b; std::transform(la.begin(), la.end(), la.begin(), ::tolower); std::transform(lb.begin(), lb.end(), lb.begin(), ::tolower); return la < lb; }
中文或 Unicode 字符串不能靠默认 sort
std::string 存的是 UTF-8 字节序列,std::sort 按字节比较,对中文会得到乱序结果(比如“你好”和“世界”按 UTF-8 首字节比,毫无语义)。
真正做中文排序,得先用 ICU、Boost.Locale 或 C++20 的 <locale></locale> 解析成 Unicode 码点,再按 locale 规则(如拼音、笔画)排序。这已超出 std::sort 能力范围。
- 最简规避方式:用
std::u32string存码点,再排序(但丢失 locale 意义,只是“Unicode 码点序”): std::u32string s = U"你好世界"; std::sort(s.begin(), s.end()); // 按 U+4F60、U+597D... 升序
- 生产环境中文排序,请直接用 ICU 的
Collator类,别自己造轮子。
性能注意:避免在 comparator 里做重复转换
如果写了一个把字符串全转小写再比较的 comparator,每次比较都调用 std::transform,时间复杂度会从 O(n log n) 退化到 O(n² log n)——尤其字符串多、长时明显卡顿。
- 正确做法是预处理:提前把“排序键”(如小写形式)缓存好,再排序:
std::vector<std::pair<std::string, std::string>> keyed; for (const auto& s : v) { std::string key = s; std::transform(key.begin(), key.end(), key.begin(), ::tolower); keyed.emplace_back(key, s); } std::sort(keyed.begin(), keyed.end()); std::vector<std::string> result; for (const auto& p : keyed) result.push_back(p.second);- 或者用 C++20 的
std::ranges::sort+ 投影(projection),更简洁: std::ranges::sort(v, {}, [](const std::string& s) { std::string key = s; std::transform(key.begin(), key.end(), key.begin(), ::tolower); return key; });
实际项目里,“字典序”三个字背后藏着 locale、编码、性能三道坎。多数时候 std::sort 开箱即用,但一旦涉及大小写、中文、长列表,就得立刻停下来想清楚:你到底要排什么意义上的“序”。


















