生成随机字母数组并计算出现次数

Generate random letter array and count occurences

您好,我正在尝试生成用户输入长度的随机数组。然后我的数组应该打印并显示数组中这些字母的出现。到目前为止,这只打印到字母 g,并且出现的次数不正确。如果有人能告诉我我做错了什么,那会有很大帮助。谢谢。

#include <iostream>
#include <cstring>
#include <ctime>
#include <cstdlib>

using namespace std;


int main()
{
    srand(time(0));
    int i, num;
    char ch;
    char chars[]={'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'};
    int freq[26]={0};
    cout << "How many letters do you want in your string? ";
    cin >> num;

    for (i=0; i < num; i++)
    {
        ch = chars[rand()%26];
        chars[i]=ch;
        freq[i] +=1;
        cout << ch;
    }

    for (char lower = 'a'; lower <='z'; lower++)
    {
        cout << "\nLetter" << lower << "is " << freq[lower] << "times";
    }
}

问题 1

线条

chars[i]=ch;
freq[i] +=1;

不对。您需要使用:

int index = ch - 'a';
freq[index] += 1; 

问题 2

用于打印数据的 for 循环中的索引也不正确。

您需要使用:

for (char lower = 'a'; lower <='z'; lower++)
{
    int index = lower - 'a';
    cout << "\nLetter" << lower << "is " << freq[index] << "times";
}

重要提示

值得注意的是,C++标准并不保证小写字母是连续的。 (感谢@MartinBonner)。例如,如果您的系统使用 EBCDIC encoding,您的程序将无法运行。

为了使您的代码健壮,最好使用 std::map

int main()
{
    srand(time(0));
    int i, num;
    char ch;
    char chars[]={'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'};

    std::map<char, int> freq;

    // Initialize freq.
    for ( ch : chars )
    {
       freq[ch] = 0;
    }

    cout << "How many letters do you want in your string? ";
    cin >> num;

    for (i=0; i < num; i++)
    {
        ch = chars[rand()%26];
        freq[ch] +=1;
    }

    for (auto item : freq )
    {
        cout << "\nLetter" << item.first << "is " << item.second << "times";
    }
}

您不应该写入 chars,并且 freq 应该被扩展以覆盖 a...z 范围(ASCII 代码),但事实并非如此。此外,在索引 ch 处增加,而不是在 i.

处增加

我什至不知道我头脑中的那个范围,但可以修改它以跟踪所有可能的字节而不是 (0...255),请参阅 https://ideone.com/xPGls7[=22= 上的结果] 变更列表:

int freq[256]={0}; // instead of int freq[26]={0};
// chars[i]=ch; is removed
freq[ch] +=1; // instead of freq[i] +=1;

然后就可以了。

你可能想看看 C++11 Pseudo-random number generation 这里有一个生成你想要的范围的简短方法:

#include <algorithm>
#include <array>
#include <random>
#include <vector>

using namespace std;

int main()
{
    int arraySize = 35;

    mt19937 engine{random_device{}()};

    uniform_int_distribution<> dist{'a', 'z'};

    vector<char> vec;

    generate_n(back_inserter(vec), arraySize, [&]() { return static_cast<char>(dist(engine); }));

    //To count occurrences 

    array<int, 26> freq;

    for (auto c : vec) { ++freq[c-'a']; }

    return 0;
}

使用 lambda 函数完成大部分工作。

#include <algorithm>
#include <functional>
#include <iostream>
#include <map>
#include <numeric>
#include <ostream>
#include <random>
#include <string>
#include <utility>
#include <vector>

using namespace std::string_literals;

int main()
{
    std::mt19937::result_type seed = std::random_device{}();
    auto engine = std::mt19937(seed);
    auto dist = std::uniform_int_distribution<>('a', 'z');
    auto random_letter = [&engine, &dist]() { return static_cast<char>(dist(engine)); };

    std::cout << "How many letters do you want to generate? "s;
    int n;
    if (!(std::cin >> n)) { return EXIT_FAILURE; }

    auto letters = std::vector<char>();
    std::generate_n(std::back_inserter(letters), n, random_letter);

    auto zero = std::map<char, int>();
    auto const frequencies = std::accumulate(std::cbegin(letters), std::cend(letters), zero, 
        [](auto& acc, auto c)
        { 
            ++acc[c]; 
            return acc;
        });

    for (auto const [c, freq] : frequencies)
    {
        std::cout << "The letter '"s << c << "' appeared "s << freq << " times." << std::endl;
    }

    return 0;
}