优先选 std::unordered_map 统计字符频次,因其平均 O(1) 时间复杂度;需 ASCII 排序时才用 std::map;注意大小写区分、空格标点独立计数;避免对空串或含 '\0' 串使用 map[ch]++;UTF-8 多字节字符需专用处理;降序输出须转 vector 后按 second 排序。

用 std::map 或 std::unordered_map 统计字符频次
直接遍历字符串,对每个 char 做计数是最直观的方式。优先选 std::unordered_map<char int></char>,因为不需排序,插入和访问平均是 O(1);如果后续要按 ASCII 顺序输出,才考虑 std::map(自动升序)。
注意:std::string 中的空格、标点、大小写字母都算独立字符,'A' 和 'a' 不同。若需忽略大小写,得先统一转成小写再计数。
- 别用
map[ch]++对空字符串或含 null 字符('\0')的输入做操作——它会意外插入键值对,干扰后续逻辑 - 如果字符串含 UTF-8 多字节字符(如中文),
char级统计会拆开字节,结果错误;此时必须用std::u8string+std::utf8_codecvt_facet或第三方库(如 ICU),但绝大多数场景只处理 ASCII
按频次降序生成新字符串
不能直接对 map 排序(key 是字符,不是频次),得把频次信息抽出来。推荐用 std::vector<:pair int>></:pair> 存映射,再用 std::sort 按 .second 降序排列:
std::vector<std::pair<char, int>> freqVec(map.begin(), map.end());
std::sort(freqVec.begin(), freqVec.end(), [](const auto& a, const auto& b) {
return a.second > b.second;
});
常见错误:用 std::greater 直接排序 pair,默认比的是 .first(字符),不是频次。
立即学习“C++免费学习笔记(深入)”;
- 频次相同时,若要求字符 ASCII 升序排列,lambda 里加二级条件:
a.second != b.second ? a.second > b.second : a.first - 构建结果字符串时,用
result.append(count, ch)比循环 push_back 更高效
处理空输入、全相同字符等边界情况
空字符串、单字符、所有字符频次相同这三种情况,代码必须不崩且输出符合预期。例如输入 "aaa",输出仍是 "aaa";输入 "",输出空串。
- 别在统计前盲目调用
s.empty()就 return,因为for (char c : s)对空串天然安全,无需提前拦截 - 如果输入含不可见控制字符(如
'\t'、'\n'),它们也会被统计并输出——这不是 bug,是符合题意的行为;若业务要求过滤,得额外判断std::isprint(c)
性能敏感时改用固定数组代替 map
若确定输入只含 ASCII 可见字符(32–126),用 int freq[128] = {} 替代 map,省去哈希/红黑树开销,O(n) 时间 + O(1) 空间。
操作方式:遍历字符串,执行 freq[(unsigned char)c]++(强转避免负索引);之后遍历 32 到 126,收集非零项再排序。
- 不要用
freq[c]——当c是signed char且值为负(如扩展 ASCII 的 128–255),会越界 - 这个优化只适用于已知字符集范围的场景;一旦输入可能含 Unicode 或任意字节,必须退回 map 方案


















