用std::unordered_map统计词频最直接高效,需正则分词并转小写,归一化或截断频率后用setw和string生成ASCII直方图。

用 std::unordered_map 统计词频最直接,但要注意分词边界
直接用 std::unordered_map<:string int></:string> 存词和次数没问题,但“词”定义不明确会导致统计失真。英文通常按空格+标点切分,中文需额外处理(本文默认英文或空格分隔文本)。别用 std::map——它强制排序,纯浪费时间;unordered_map 平均 O(1) 插入查找,实测快 2–3 倍。
常见错误是用 std::stringstream 简单 operator>> 读单词,会吞掉连续空格、丢掉行首/尾词,还无法过滤标点。建议用 std::regex 或手动遍历:
std::regex word_regex(R"(\b[a-zA-Z]+\b)");
auto words_begin = std::sregex_iterator(text.begin(), text.end(), word_regex);
auto words_end = std::sregex_iterator();
for (std::sregex_iterator i = words_begin; i != words_end; ++i) {
std::string word = i->str();
std::transform(word.begin(), word.end(), word.begin(), ::tolower);
freq[word]++;
}生成直方图前先做频率归一化或截断,否则小词淹没在大词里
原始频次范围可能极大(比如 “the” 出现 500 次,“algorithm” 只有 3 次),直接画柱状长度会失真。两种实用策略:
- 取 top-K(如 K=20),只画高频词——用
std::partial_sort_copy配自定义比较器,比全排序快 - 线性缩放到固定宽度(如 50 字符),公式:
int bar_width = std::min(50, (freq[word] * 50) / max_freq);注意max_freq为 0 时要防除零 - 若想视觉更均衡,改用对数缩放:
int bar_width = static_cast<int>(log2(freq[word] + 1) * 8)</int>,加 1 避开 log(0)
输出 ASCII 直方图时,std::setw 和 std::left 控制对齐更可靠
别手写循环拼空格——易错且难维护。用 <iomanip> 的 std::setw 和 std::left 对齐词名,再用 std::string(bar_width, '#') 生成条形:
立即学习“C++免费学习笔记(深入)”;
for (const auto& [word, count] : top_words) {
int bar_width = std::min(40, static_cast<int>((count * 40) / max_count));
std::cout << std::left << std::setw(16) << word
<< " |" << std::string(bar_width, '#') << "\n";
}注意:如果词长超 16,std::setw(16) 不会截断,而是撑开字段,导致后续对齐错位。稳妥做法是先 word.substr(0, 15) + "." 截断,或动态算最大词长再设宽。
性能敏感场景下,避免重复构造 std::string 和小对象拷贝
高频调用时,每次 freq[word]++ 会触发 std::string 拷贝;若文本巨大,可改用 std::string_view(C++17)作 key:
std::unordered_map<std::string_view, int> freq; // 注意:string_view 必须指向生命周期长于 map 的字符串,比如 const std::string& text
但 std::string_view 不能直接用于 std::regex_iterator 结果(其 i->str() 返回临时 std::string),得先存到 std::vector<:string></:string> 再转 view,权衡取舍。另外,VS2019 及更早版本对 string_view hash 支持不完整,编译报错时回退用 std::string。
真正卡顿往往不在统计本身,而在输出——尤其终端渲染大量 # 字符时。如果直方图只是调试用,考虑只输出前 10 行;生产环境导出 CSV 或交给 gnuplot 更实际。


















