用std::unordered_map统计词频最直接,但需先用regex提取单词并转小写,再插入;降序排序须导出至vector后自定义sort;中文分词需第三方库且必须utf-8编码处理。

用 std::unordered_map 统计词频最直接,但要注意分词边界
纯 C++ 标准库不自带“按空格/标点分词”功能,std::string 的 find_first_of 或 std::stringstream 都可能漏掉连续分隔符(比如多个空格、换行混用),导致把空字符串当词统计。实际项目中建议先做清洗:用 std::regex 匹配 \w+(或更严格的 [a-zA-Z]+)提取单词,忽略大小写时统一转小写再插入 std::unordered_map<:string int></:string>。别用 std::map——它默认按 key 排序,但排序发生在插入时,O(log n) 开销叠加后整体是 O(n log n),而降序需求在最后一步才需要。
降序排序必须脱离 map,用 std::vector + std::sort
std::unordered_map 本身无序,不能靠修改比较器让它“自动降序”。正确做法是把键值对搬进 std::vector<:pair int>></:pair>,再用 lambda 自定义排序:
std::sort(freqVec.begin(), freqVec.end(),
[](const auto& a, const auto& b) {
return a.second != b.second ? a.second > b.second : a.first <p>这里注意两点:第一,按频次降序;第二,频次相同时按字典升序,避免相同频次的词顺序不稳定(影响可复现性)。别忘了加 <code>#include <algorithm></algorithm></code> 和 <code><vector></vector></code>。</p><h3>生成分布图?C++ 本身不绘图,得靠外部工具导出数据</h3><p>C++ 没有内置图表库,所谓“生成降序分布图”本质是输出结构化数据供其他工具消费。推荐写成 CSV 或 JSON:</p><div class="aritcle_card flexRow artxards">
<div class="artcardd flexRow">
<a class="aritcle_card_img" rel="nofollow" href="/xiazai/gongju/2823" title="C++14"><img
src="https://img.php.cn/upload/manual/001/431/639/6ac8b33c327c4749.png" alt="C++14" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a>
<div class="aritcle_card_info flexColumn">
<a rel="nofollow" href="/xiazai/gongju/2823" title="C++14" class="overflowclass">C++14</a>
<p class="overflowclass">C++14 对 C++11 的修正与增强版本,适合旧系统维护和较老工具链兼容。</p>
</div>
<a rel="nofollow" href="/xiazai/gongju/2823" title="C++14" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span>
</a>
</div>
</div>
- CSV 更简单:
std::ofstream每行写word,frequency,用逗号分隔,Excel / Python pandas 都能直接读 - JSON 更通用:用轻量级库如
json.hpp(single-header)序列化为数组对象,字段名统一为"word"和"count" - 别手写 JSON 字符串拼接——引号、转义、嵌套易出错
如果硬要在终端画个简易柱状图(比如用字符 * 表示频次),注意最大频次可能过大,需归一化到固定宽度(如 50 个 *),否则一行超长刷屏。
性能陷阱:频繁 std::string 拷贝和小字符串优化失效
高频词统计中,每个词插入 map 时都会触发 std::string 拷贝。若原始文本很大且词短(如英文单字),启用小字符串优化(SSO)的编译器(如 GCC/Clang 默认开启)能避免堆分配,但 MSVC 在某些版本下 SSO 阈值不同。更稳妥的做法是用 std::string_view 做临时视图,仅在确认要存入 map 时才构造 owned string:
std::string_view token = /* 提取的子串 */; auto it = freqMap.find(token); if (it != freqMap.end()) it->second++; else freqMap.emplace(std::string(token), 1);
另外,预估容量能减少 rehash:读完全部文本后调用 freqMap.reserve(expected_unique_word_count),避免多次扩容抖动。
真正麻烦的是中文分词——C++ 没标准方案,得集成第三方库(如 cppjieba),且编码必须统一为 UTF-8,std::string_view 切分时不能按字节索引,得用 ICU 或 utf8cpp 解码后再处理。这点容易被忽略,一上来就用 substr(0,1) 切中文,结果全是乱码或截断。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










