我之前的所有答案都没有给出真正的答案。
让我们考虑一个潜在的解决方案。
有一种或多或少的标准方法来计算容器中的东西。
我们可以使用std::map 或std::unordered_map 之类的关联容器。在这里,我们将一个“键”(在本例中为单词)与一个计数与一个值(在本例中为特定单词的计数)相关联。
幸运的是,这些地图有一个非常好的索引operator[]。这将查找给定的键,如果找到,则返回对该值的引用。如果未找到,则它将使用密钥创建一个新条目并返回对新条目的引用。因此,在这两种情况下,我们都会获得对用于计数的值的引用。然后我们可以简单地写:
std::unordered_map<char,int> counter{};
counter[word]++;
这看起来非常直观。
经过这个操作,你已经有了频率表。按键(单词)排序,使用std::map 或未排序,但使用std::unordered_map 可以更快地访问。
现在您想根据频率/计数进行排序。不幸的是,这在地图上是不可能的。
因此,我们需要使用第二个容器,例如 ```std::vector`````,然后我们可以为任何给定的谓词排序 unsing std::sort,或者,我们可以将值复制到容器中,就像 std::multiset 隐含地对其元素进行排序。
为了取出std::string 的单词,我们只需使用std::istringstream 和标准提取运算符>>。没什么大不了的。
由于为 std 容器编写了所有这些长名称,我们创建了别名,使用 using 关键字。
在这一切之后,我们现在编写超紧凑的代码,只需几行代码即可完成任务:
#include <iostream>
#include <string>
#include <sstream>
#include <utility>
#include <set>
#include <unordered_map>
#include <type_traits>
#include <iomanip>
// ------------------------------------------------------------
// Create aliases. Save typing work and make code more readable
using Pair = std::pair<std::string, unsigned int>;
// Standard approach for counter
using Counter = std::unordered_map<Pair::first_type, Pair::second_type>;
// Sorted values will be stored in a multiset
struct Comp { bool operator ()(const Pair& p1, const Pair& p2) const { return (p1.second == p2.second) ? p1.first<p2.first : p1.second>p2.second; } };
using Rank = std::multiset<Pair, Comp>;
// ------------------------------------------------------------
std::istringstream text{ " 4444 55555 1 22 4444 333 55555 333 333 4444 4444 55555 55555 55555 22 "};
int main() {
Counter counter;
// Count
for (std::string word{}; text >> word; counter[word]++);
// Sort
Rank rank(counter.begin(), counter.end());
// Output
for (const auto& [word, count] : rank) std::cout << std::setw(15) << word << " : " << count << '\n';
}