推荐用 std::unordered_map 统计频率后配合 lambda 比较函数调用 std::sort 原地重排,引用捕获频次映射,频次相同时可加次级排序规则;注意排序会打乱原序且禁止在排序中修改映射。

用 std::map 或 std::unordered_map 统计频率再排序
直接对原数组按频率排序,本质是「先计数、再重排」。C++ 没有内置的「按频次排序数组」函数,必须分两步:先用哈希表统计每个值出现次数,再基于频次对原数组(或值集合)重排序。
推荐优先用 std::unordered_map,因为插入和查找平均 O(1),比 std::map 的 O(log n) 更快;但如果需要键有序(比如后续要遍历所有唯一值),才选 std::map。
注意:如果数组里有负数、大整数或自定义类型,std::unordered_map 仍可用,但需确保该类型支持哈希(基础类型如 int、long long 默认支持)。
用 std::sort 配合自定义比较函数实现原地重排
排序目标不是让频次数组升序,而是让原数组中元素按「自身出现频次升序/降序」排列;相同时可加次级规则(如值本身升序),避免不稳定。
立即学习“C++免费学习笔记(深入)”;
- 必须传入频率映射作为捕获上下文,所以比较函数得是 lambda(或 functor),不能是普通函数指针
- 捕获方式推荐
[&freq](引用捕获),避免拷贝整个 map - 若频次相同,默认
std::sort不保证相对顺序(不稳定),加次级比较可控制:a != b ? freq[a]
示例(降序频次,频次相同时升序值):
std::vector<int> arr = {4, 5, 6, 5, 4, 4};
std::unordered_map<int, int> freq;
for (int x : arr) freq[x]++;
std::sort(arr.begin(), arr.end(), [&freq](int a, int b) {
if (freq[a] != freq[b]) return freq[a] > freq[b];
return a < b;
});
用 std::vector + std::pair 提前提取唯一值再排序更可控
上面原地排序会重复查 map、且无法轻易去重。如果最终只需要「按频次排列的唯一值列表」(比如 Top-K 频次元素),更推荐先提取键值对,再排序:
- 构造
std::vector<:pair int>></:pair>,存{value, count} - 用
std::sort对这个 vector 排序,比较逻辑清晰,无重复查表开销 - 避免原数组中高频值被多次输出(比如
4出现 3 次,你可能只想要一次4)
示例(取频次降序前 3):
std::vector<std::pair<int, int>> pairs;
for (const auto& p : freq) pairs.push_back(p);
std::sort(pairs.begin(), pairs.end(), [](const auto& a, const auto& b) {
return a.second > b.second; // 频次降序
});
// pairs[0].first 就是最高频的值
注意 std::sort 的稳定性与迭代器失效风险
对原数组调用 std::sort 是就地操作,不改变大小,但会打乱原始顺序——这在某些场景下是副作用,比如你需要保留「首次出现位置」信息。
如果后续还要按原顺序处理(例如输出「每个高频值第一次出现的索引」),就不能只靠排序后的数组,得额外记录索引映射。
另一个坑:别在排序过程中修改 freq map,否则 lambda 里引用的 freq[a] 可能访问未定义行为(尤其是 freq 发生 rehash 时);统计必须在 sort 前完成且不再写入。


















