使用地图容器的字母频率

时间:2018-11-05 11:47:31

标签: c++ class dictionary data-structures

我试图通过使用地图容器作为数据结构来定义一个名为Frequency的类。该类旨在从键盘读取字符并计算已输入的每个字符的频率。

This

这显示了频率类的UML图。 函数printFreqTable应该输出每个输入字符的频率,如示例输出所示:

Enter your string without spaces: textEPF
Char   Frequency
E      *
P      *
F      *
t      **
e      *
x      *

但是,我的实现未产生任何输出,并且存在代码-1073741819。我还想知道是否有使用地图容器的更有效的实现方法。

#include <iostream>
using namespace std;
#include <map>
#include <string>
#include <vector>

class Frequency {
public:
    Frequency();
    void insertStringtoMap();
    void printFreqTable();
    void readString();
private:
    typedef map <char, string, less <char > > mid;
    mid CMap;
    string s;
};

Frequency::Frequency()
{
    readString();
}

void Frequency::readString()
{
    cout << "Enter your string without spaces: ";
    getline(cin, s);
    cout << endl;
}

void Frequency::insertStringtoMap()
{
    int si = s.size();
    char str[50];
    strcpy_s(str, s.c_str());
    string freq = 0;

    for (char ch = 65; ch <= 122; ch++) {
        int c = 0;
        for (int i = 0; i < si; i++)
        {
            if (ch == str[i])
            {
                c++;
            }
        }
        if (c > 0)
        {
            for (int star = 0; star < c; star++)
            {
                freq = freq + "*";

            }       
            CMap.insert(mid::value_type(ch, freq));
        }
    }
}

void Frequency::printFreqTable()
{
    cout << "Char\tFrequency";
    for (auto iter = CMap.cbegin(); iter != CMap.end(); ++iter)
        {
            cout << iter->first << "\t"
            << iter->second << "\n";
        }
}

int main()
{
    Frequency f;
    f.insertStringtoMap();
    f.printFreqTable();
}

3 个答案:

答案 0 :(得分:0)

我已改为计算每个字符的出现,而不是直接构建图形表示。计数完成后,我使用了std :: string的功能来创建带有n个特定字符副本的字符串,以创建图表。

#include <iostream>
#include <map>
#include <string>
#include <vector>

class Frequency {
public:
    Frequency();
    void insertStringtoMap();
    void printFreqTable();
    void readString();
private:
    typedef std::map<char, size_t> mid;
    mid CMap;
    std::string s;
};

Frequency::Frequency() :
    CMap(),
    s()
{
    readString();
}

void Frequency::readString()
{
    std::cout << "Enter your string without spaces: ";
    std::getline(std::cin, s);
    std::cout << std::endl;
}

void Frequency::insertStringtoMap() {
    for(auto ch : s) {
        ++CMap[ch];
    }
}

void Frequency::printFreqTable()
{
    std::cout << "Char\tFrequency\n";
    for (const auto& e : CMap)
    {
        std::cout << e.first << "\t" << std::string(e.second, '*') << "\n";
    }
}

int main()
{
    Frequency f;
    f.insertStringtoMap();
    f.printFreqTable();
}

答案 1 :(得分:0)

您的代码存在三个问题。
第一:

string freq = 0; //Assigning an int literal to a string? 

它应该简单地是:

string freq;

第二:
这应该在for旁边的第一个int c = 0;循环中,以便您重置每个字符的* s个计数。

for (char ch = 65; ch <= 122; ch++) {
    int c = 0;
    string freq;

第三:
只是为了使输出看起来更好,在此语句中添加新行,如下所示:

cout << "Char\tFrequency\n";

输出:

Enter your string without spaces: asdsadfkdfgag

Char    Frequency
a       ***
d       ***
f       **
g       **
k       *
s       **

作为一个好习惯,请停止使用using namespace std。请参阅此问题及其答案:Why is "using namespace std" considered bad practice?

答案 2 :(得分:0)

我认为您一次尝试做太多事情而感到困惑。

将问题分为两部分:读取字符串并将每次出现的事件存储在地图中,并以漂亮的格式打印结果地图。

现在,您可以轻松地将字符串解析到地图中,只需循环遍历每个字符并向地图添加一个条目-可以是任何东西,因此std::map<char, int>将针对每个字符串存储一个int(即出现次数)键输入,可以是字符本身

通过解析地图条目并增加值来做到这一点,例如mymap[letter]++mymap.find(letter) += 1

然后通过遍历地图,打印与int值相同数量的星星来进行格式化。

(以伪代码:)

std::map<char,int>::iterator i = mymap.begin()
while (i != mymap.end()) {
  cout i.first << "*" (i.second) times << endl;
  i++;
}

不要在地图上存储*字符串,只需记下出现的次数,并在需要时使用它生成星号即可。这样效率更高,而且您也可以非常轻松地更改格式。

注意:在地图上使用typedef,这会使外观和读取更加容易。 Std :: string具有一个构造函数,可以轻松地在字符串中生成许多星星。