【问题标题】:How to print frequency of each letter in a string in descending order c++?如何按降序打印字符串中每个字母的频率c ++?
【发布时间】:2018-06-24 03:37:46
【问题描述】:
#include <iostream>
#include <string>
using namespace std;
int main () {
    int cnt[26] {};
    char alpha[26];
        string s = "abcdefffggghiii";
        for (int i = 0; i < s.length(); i++) {
                cnt[s[i] - 'a']++;
        }

    for (int i = 'a'; i <= 'z'; i++) {
        alpha[i - 'a'] = i;
    }
    for (int i = 0; i < 26; i++) {
        if (cnt[i]) {
            cout << alpha[i] << " " << cnt[i] << endl;
        }
    }

    return 0;
}

我想按降序打印字符串中每个字母的频率。我曾考虑对 cnt 数组进行排序并从25 打印到0,但它只会打印带有错误字母的频率。如何修复它以降序打印例如 i 3 等等?

【问题讨论】:

  • cnt 数组进行排序将丢失元素的原始索引,因此您需要以某种方式跟踪它。此外,从字母中减去 'a' 不能保证为所有字符集提供介于 025 之间的值(它适用于 ASCII 或兼容字符集,但不适用于其他字符集)。

标签: c++ string


【解决方案1】:
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;

int main() {

  // Create result container    
  auto x = vector<pair<char, int>>();

  std::string s = "abcdefffggghiii";
  for (auto& l : s) {    
    // Find the item that corresponds to letter
    auto pLetter =
        find_if(x.begin(), x.end(), [&l](pair<char, int> &arg) {
          return arg.first == l;
        });

    if (pLetter != x.end())
      pLetter->second++;   // If item corresponding to letter is found, increment count
    else {
      x.push_back(make_pair(l, 1)); // Otherwise, create a new result entry
    }
  }

  // Sort results by count in descending order
  std::sort(x.begin(), x.end(),
            [](auto &left, auto &right) { return left.second > right.second; });

  for (auto i = x.begin(); i != x.end(); ++i)
    std::cout << i->first << ':' << i->second << '\n';
}

生产

f:3
g:3
i:3
a:1
b:1
c:1
d:1
e:1
h:1

您可以运行它here。这将 C++14 lambda 用于 find_if 和排序谓词。此解决方案与@Retired Ninja 的解决方案非常相似,不同之处在于结果向量仅包含那些具有非零计数的字母的项目。这意味着它可以扩展到 wstrings,而不需要大的结果向量。

【讨论】:

    【解决方案2】:

    我可以这样做。您只需要将字母和计数放在一起即可。

    #include <iostream>
    #include <vector>
    #include <string>
    #include <algorithm>
    
    struct LetterFreq
    {
        char letter;
        int freq;
    };
    
    int main()
    {
        std::vector<LetterFreq> cnt(26);
        for (size_t i = 0; i < cnt.size(); ++i)
        {
            cnt[i].freq = 0; 
            cnt[i].letter = static_cast<char>(i) + 'a';
        }
        std::string s = "abcdefffggghiii";
        for (auto& l : s)
        {
            cnt[l - 'a'].freq++;
        }
        std::sort(cnt.begin(), cnt.end(), [](const LetterFreq& lhs, const LetterFreq& rhs) 
        { 
            return lhs.freq > rhs.freq; 
        });
        for (auto& item : cnt)
        {
            if (item.freq == 0)
            {
                break;
            }
            std::cout << item.letter << " : " << item.freq << "\n";
        }
        return 0;
    }
    

    如果你只有小写的 ASCII 字母,这很简单。对于更复杂的输入,您可以在结构中使用相同的字母和计数概念,但您要么希望将向量的大小增加到 256 以跟踪所有可能性,要么使用无序映射之类的东西只存储使用过的符号,然后将它们复制到可以排序以显示它们的容器中。您还可以使用并行数组,在排序的同时交换字母位置,同时交换计数。有很多方法可以解决这个问题。

    【讨论】:

    • std::sort(cnt.begin(), cnt.end(), [](const LetterFreq&amp; lhs, const LetterFreq&amp; rhs) { return lhs.freq &gt; rhs.freq; });这个功能我没见过,是c++ 14的吗?
    • 这是一个 lambda 函数。你需要 C++11。 stackoverflow.com/questions/7627098/… 我在课堂上讨论过使用它还是重载operator&gt;,并认为任何一种方式都可能令人困惑。 lambda 可以做的比那个简单的要多得多,但对于排序来说,它往往会为运算符或函数节省大量样板代码,并且代码就在你可以看到的地方。
    【解决方案3】:

    您可以使用对,但看起来您正在使用更基本的类型来执行此操作。在这种情况下,您可能必须使用嵌套循环。继续寻找频率最高的字符,打印出来,然后将它的频率设置为-1,表示你已经处理过了。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-08-30
      • 2012-05-20
      • 2019-03-26
      • 2012-06-04
      • 1970-01-01
      • 2021-02-21
      • 1970-01-01
      相关资源
      最近更新 更多