4

我想用 C++ 编写一个函数,它计算字符串中的所有字符。# 我有一个称为输入的字符串,程序的用户可以在其中输入一个句子,重要的字母我存储在这样的字符串字母表中:

string alphabet {"ABCDEFGHIJKLMNOPQRSTUVWXYZ"};

以及用于存储字母出现频率的向量,例如 A 位于位置 0,B 位于位置 0,以此类推。

vector<long> letterCount (26);

我已经编写了我认为应该可以工作的函数,并且它似乎能够找出字符的出现,但之后这个数字乘以字母在字母表中的位置。这是功能:

long countLetters(int& p) {
  for(int i = 0; i < alphabet.size(); ++i) {
      for(long j = 0; j < count(input.begin(), input.end(), alphabet.at(i)) {
          countLetters.at(i)++;
      }
  }
return letterCount.at(p);
}

例如,如果输入是“HELLO”,程序会输出:

E : 5
H : 8
L : 24
O : 15

所以你看,例如字母'L'在字符串中包含两次,但'L'的结果是24,因为'L'在字母表中的第12位。

请帮忙,如果你意识到我的问题是什么。

编辑:我找到了一种有效的方法,至少部分有效:

long countLetters(int& p) {
   for(size_t i = 0; i < input.length(); ++i) {
      for(size_t j = 0; j < alphabet.length(); ++j) {
        letterCount.at(j) = count(input.begin(), input.end(), alphabet.at(j));
      }
   }
   return letterCount.at(p);
 }

但是当输入两个或更多单词时,该函数只计算出第一个单词中出现的字母。如何分析更多单词?

编辑:之前我有cin >> input但是getline(cin, input);是对的。

4

10 回答 10

4

你正在做某种奇怪的双循环。相反,在单个循环中迭代字符串并将其计入正确的组中:

for (int i = 0; i < input.length(); i++) {
    char c = input[i];
    if (c < 'A' || c > 'Z') continue;
    countLetters[c-'A'] += 1;
}
于 2013-07-13T09:11:15.327 回答
2

我将分两步执行此操作:

#include <unordered_map>
#include <algorithm>
#include <string>
#include <iostream>

int main()
{
    std::string alphabet = "abcdefghijklmnopqrstuvwxyz";
    std::string input = "hello world";
    std::unordered_map<char, unsigned int> counts;
    std::unordered_map<char, unsigned int> counts2;
    std::for_each(std::begin(input), std::end(input), [&counts](char c) {
        counts[c]++;
    });
    std::for_each(std::begin(alphabet), std::end(alphabet), [&counts, &counts2] (char c) {
        const auto& it = counts.find(c);
        if( it != counts.end()) counts2.insert(*it);        
    });
    for(auto& kv: counts2)
    {
        std::cout << kv.first << ": " << kv.second << "\n";
    }
    return 0;
}

由于对无序映射的访问应该按顺序进行,O(1)这将导致复杂度为O(N+M)N即输入字符串M的长度和输出字符串的长度。您也许可以改进 counts 和 counts2 之间的复制,或者完全消除额外的地图,我在写这篇文章时有点着急;)。您也可以返回将输出放入向量中,但我将把它留作练习。

另一种变体是将您的字母表存储在一组中,并if(alphabetset.count(c))在第一个循环中执行,而不执行第二个循环。这将具有复杂性O(N*log(M)),也可以足够好,并且代码更简单一些:

#include <unordered_map>
#include <algorithm>
#include <string>
#include <iostream>
#include <set>

int main()
{
    std::string alphabet = "abcdefghijklmnopqrstuvwxyz";
    std::set<char> alphabetset{std::begin(alphabet), std::end(alphabet)};
    std::string input = "hello world";
    std::unordered_map<char, unsigned int> counts;
    std::for_each(std::begin(input), std::end(input), [&counts, &alphabetset](char c) {
        if(alphabetset.count(c)) counts[c]++;
    });
    for(auto& kv: counts)
    {
        std::cout << kv.first << ": " << kv.second << "\n";
    }
    return 0;
}

当然,如果您的输入集具有一些数学属性(例如精确范围),您可以使用 Tom van der Woerdt 之类的解决方案,因为这将是O(N)并且您无法比这更快。

于 2013-07-13T09:43:49.050 回答
1

这是我解决问题并按降序打印结果的版本。

void printNumofLetterinString(std::string sentence){
    int frequencyArray[26];         //FrequencyArray is used to store the frequency
    for(int i=0;i<26;i++){          //of the letters and Initialize 
        frequencyArray[i] = 0;      //frequencyArray to all zero.
    }
    int ascii;
    for(int i=0;i<sentence.length();i++){
        if(!isalpha(sentence[i])){
            continue;
        }
        ascii = tolower(sentence[i]) - 'a';   //Convert A-Za-z to number between 0-25.
        frequencyArray[ascii]++;
    }
    for(int i=0;i<26;i++){              //Find the biggest number in frequencyArray     
        int max = frequencyArray[0];    //print it, then set it to zero  
        int index = 0;                  //and find the next biggest number.
        for(int j=0;j<26;j++){
            if(frequencyArray[j] > max){
                max = frequencyArray[j];
                index = j;
            }
        }
        if(max == 0){
            break;
        }
        char c = index + 'a';
        std::cout<<c<<" "<<max<<std::endl;
        frequencyArray[index] = 0;
    }
}

结果如下所示

input caaabb
output a 3
       b 2
       c 1
于 2014-10-25T17:45:34.363 回答
1
char arr[] = {"aaabbaccdaadac"}; 
    map<char,int> mymap;
    for(int i= 0 ;i<strlen(arr);i++)
    {            
        mymap.insert(pair<char,int>(arr[i],0));
          auto it = mymap.find(arr[i]);
          ++it->second;
          mymap.insert(pair<char,int>(arr[i],it->second));

     }

    map<char, int> ::iterator mapit;
    for(mapit = mymap.begin(); mapit != mymap.end() ; mapit++)
    {
        cout<<mapit->first<< "   occurence   ==  " <<mapit->second<<endl;
    }
于 2016-02-18T09:15:46.703 回答
1

该字符串可以作为来自用户的参数。

cin >> inputString;

unordered_map<char, int> characterMap;

for (char c : inputString){
    characterMap[c]++;
}
for (std::pair<char, int> characterCount : characterMap) { // Alternatively use 'auto' as type
    cout << characterCount.first << " count: " << characterCount.second << endl;
}
于 2018-06-28T10:53:28.023 回答
0

正如@KillianDS 在评论中提到的那样,如果您想要一个通用解决方案(即可以变化的“字母表”),最简单的方法可能是计算每个可能字符的出现次数,然后根据您的实际字母表进行过滤:

// count every possible character
std::array<size_t, (1 << (8 * sizeof(char)))> countChars;
countChars.fill(0);
for (auto i = input.begin(); i != input.end(); ++i)
    countChars[*i]++;
// extract only the ones you're interested in
std::vector<size_t> countLetters;
for (auto i = alphabet.begin(); i != alphabet.end(); ++i)
    countLetters.push_back(countChars[*i]);

注意:计数项目时,最好size_t使用longint

于 2013-07-13T09:38:41.510 回答
0

你也可以这样做:

 char   *x = "cmnasdkASFSAFASDisdajkhasdfjqwedz" ; // work UPPER , lower
 static int  c[26] ;

 int main ( void ) {

 while ( *x )   {
     int ndx= *x - (islower(*x) ? 'a' : 'A') ;
     c[ ndx] += isalpha(*x++) ? 1 : 0 ;
 }
 for ( int i =0;i<26;i++)   printf ( "\n%d", c[i] );  
}
于 2013-07-13T09:58:09.833 回答
0

你可以这样做:

std::string alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
std::string input = "MISSISSIPPI yukon.";

// First insert the characters that we want to count.
std::unordered_map<char, size_t> map;
for (auto ch : alphabet)
    map[ch] = 0;

// Then count ONLY the inserted characters.
for (auto ch : input) {
    auto it = map.find(ch);
    if (it != map.end())
        ++it->second;
}

for (auto pair : map)
    if (pair.second > 0)
        std::cout << '\'' << pair.first << "\'\t" << pair.second << std::endl;

这印...

'I'     4
'M'     1
'P'     2
'S'     4

...因为我们计算alphabet.

如果您希望保证有序的结果,请替换std::unordered_map为(在上面的示例中它们是偶然订购的)。std::map

于 2013-07-13T10:32:25.363 回答
0

测试这个宏

#define FOR_ALL(cont , block)\
for (const auto &itr : cont)\
    block;

而这部分代码

map<char, int> countLetters;
FOR_ALL(str, countLetters[itr]++);

并打印结果

for (const auto &element : m)
    cout << element.first << ' ' << element.second<<endl;
于 2017-01-18T04:03:28.407 回答
0
#include<iostream>
#include <conio.h>
using namespace std;

int main (){
char str[50];
cin.getline(str,50);
int arr[1234]={0};

///extraction of every character 
int i=0;
while(str[i]!='\0'){

arr[str[i]-' ']++;    /* converting characters into integer type implicitly 
                       and storing freq of the ASCII characters at that 
                        position of the array.' ' space char is just a 
                        reference point... */ 


i++;
}



///show character freq
for (i=0;i<256;i++) {
if (arr[i]!=0)
cout <<"letter "<<char(i+' ')<<"  is present "<<arr[i]<<" times "<<endl;

}

return 0;

}

/* the arr array contains freq of all the characters and symbols occuring in 
a string after ' '(space) character ..so beware of entering the characters 
that are before ' ' on the standard ASCII table and your program should run 
fine..if you want to do so just replace the ' ' everywhere with the first 
character of the ASCII table.....*/
于 2017-11-01T19:38:50.977 回答