我之前的所有答案都没有给出真正的答案。
让我们考虑一个潜在的解决方案。
有一种或多或少的标准方法来计算容器中的东西。
我们可以使用关联容器,例如 astd::map
或 a std::unordered_map
。在这里,我们将一个“键”(在这种情况下是单词)与一个值关联起来,在这种情况下是特定单词的计数。
幸运的是,这些地图有一个非常好的索引operator[]
。这将查找给定的键,如果找到,则返回对该值的引用。如果未找到,则它将使用密钥创建一个新条目并返回对新条目的引用。因此,在这两种情况下,我们都会获得对用于计数的值的引用。然后我们可以简单地写:
std::unordered_map<char,int> counter{};
counter[word]++;
这看起来非常直观。
完成此操作后,您已经有了频率表。要么按键(单词)排序,要么使用 astd::map
或未排序,但使用 a 可以更快地访问std::unordered_map
。
现在您要根据频率/计数进行排序。不幸的是,这在地图上是不可能的。
因此,我们需要使用第二个容器,例如 ```std::vector`````,然后我们可以对std::sort
任何给定的谓词进行排序,或者,我们可以将值复制到容器中,例如std::multiset
隐含排序的它的元素。
为了取出 a 的单词,std::string
我们只需使用 astd::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';
}