数组初始化和查找字母频率
Array initialization and finding letter frequency
我正在尝试计算字符串数组中字母出现的频率,并将频率设置为整个字母表大小的数组。我希望我已经设计了 upper/lower 个案例无关紧要的方式。在此之后,我想将频率最高的字母设置为该字母表的 'e' (因为 e 在许多语言中出现频率最高)并找出频率最高的字母和 e 之间的区别。
在我的心理演练中这似乎是有道理的,但我的编译器出于某种原因给了我断点并且根本不允许我检查它,所以我不确定出了什么问题。所以请原谅我没有发布 SSCCE。在此先感谢您的帮助!
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
int alpharay[26];
for (int i = 0; i < 26; i++)
{
alpharay[i] = 0;
}
ifstream input;
cout << "File name (.txt): ";
string fileName;
cin >> fileName;
input.open(fileName.c_str());
while (!input.eof())
{
string newLine;
getline (input, newLine);
for (int i = 0; i < newLine.length(); i++)
{
if (isalpha(newLine[i]))
{
int index;
if (isupper(newLine[i]))
{
index = newLine[i] - 'A';
alpharay[index]++;
}
else if (islower (newLine[i]))
{
index = newLine[i] - 'a';
alpharay[index]++;
}
}
}
}
//To find the largest value in array
int largest = 0;
char popular;
for (int i = 0; i < 26; i++)
{
if (alpharay[i]>=largest)
{
largest = alpharay[i];
popular = 'a' + i;
}
}
//To find the size of the shift
int shift = popular - 'e';
cout << "Shift size: " << shift << endl;
return 0;
}
问题 1:
input.open(fileName.c_str());
while (!input.eof())
需要检查文件是否打开。如果文件打不开,您将永远不会收到 EOF。
input.open(fileName.c_str());
if (input.is_open()
{
while (!input.eof())
// rest of your code
}
else
{
cout << "Couldn't open file " << fileName << endl;
}
但这只是解决了问题。除了需要注意的 EOF 之外,文件可能发生的情况还有很多。
问题 2:
while (!input.eof())
{
string newLine;
getline (input, newLine);
for (int i = 0; i < newLine.length(); i++)
那么如果 getline 读到了 EOF 呢?该程序将其作为有效行进行处理,然后测试 EOF。同样,一个简单的修复:
string newLine;
while (getline (input, newLine))
{
for (int i = 0; i < newLine.length(); i++)
// rest of loop code
}
只要读完一行,就继续。如果没有行,不管为什么,循环退出。
问题 3:
如果没有字母字符,这个循环将 return 'z':
for (int i = 0; i < 26; i++)
{
if (alpharay[i]>=largest)
{
largest = alpharay[i];
popular = 'a' + i;
}
}
简单的解决方案是 运行 循环,然后测试最大的 == 0 并打印合适的 "No letters found" 消息。
在C++中我们不应该使用C-Style数组,而应该使用C++ STL容器。并且有许多容器可用于各种用途。
例如计算元素。
有一个或多或少的标准方法来计算容器中或一般情况下的东西。
我们可以使用关联容器,例如 std::map
或 std::unordered_map
。在这里,我们将一个“键”(在本例中为要计数的字母)与一个值(在本例中为特定字母的计数)相关联。
幸运的是地图有一个非常好的索引运算符[]。这将查找给定的键,如果找到,return 对该值的引用。如果未找到,它将使用键和 return 对新条目的引用创建一个新条目。因此,在机器人案例中,我们将获得对用于计数的值的引用。然后我们可以简单地写:
std::unordered_map<char,int> counter{};
counter[c]++;
这看起来非常直观。
另外。从地图中获取最大的计数器值,可以简单地通过使用 maxheap 来实现。可以使用 std::priority_queue
在 C++ 中实现最大堆。您可以使用它的范围构造函数,用 std::unordered_map
中的值填充它。所以,一个典型的单线。现在您可以立即访问最高价值。
这样,我们就可以得到一段非常紧凑的代码了。
#include <iostream>
#include <fstream>
#include <utility>
#include <unordered_map>
#include <queue>
#include <vector>
#include <iterator>
#include <string>
#include <cctype>
// Some Alias names to ease up typing work and to make code more readable
using Counter = std::unordered_map<char, int>;
struct Comp { bool operator ()(const std::pair<char, int>& p1, const std::pair<char, int>& p2) { return p1.second < p2.second; }};
using MaxHeap = std::priority_queue<std::pair<char, int>, std::vector<std::pair<char, int>>, Comp>;
int main() {
// Get filename, open file and check, if it could be opened
if (std::string fileName{}; std::getline(std::cin, fileName)) {
if (std::ifstream fileStream{ fileName }; fileStream) {
Counter counter{};
// Read all characters from the source file and count their occurence
for (char c{}; fileStream >> c;) {
// Get lower case of letter
const char letter = static_cast<char>(std::tolower(c));
// Count occurence, if letter is an alpha value
if (std::isalpha(letter)) counter[letter]++;
}
// Build a Max-Heap
MaxHeap maxHeap(counter.begin(), counter.end());
// Show result
std::cout << "\nShift size: " << maxHeap.top().first-'e' << '\n';
}
else std::cerr << "\nError: Could not open file '" << fileName << "'\n";
}
}
用 C++17 编译
为了轻松地按排序顺序访问所有元素,您还可以使用 std::multiset
而不是 std::priority
队列。
如果你只想拥有最顶层的 n 个元素,你可以将 std::partial_sort_copy
与 std::vector
结合使用。
我正在尝试计算字符串数组中字母出现的频率,并将频率设置为整个字母表大小的数组。我希望我已经设计了 upper/lower 个案例无关紧要的方式。在此之后,我想将频率最高的字母设置为该字母表的 'e' (因为 e 在许多语言中出现频率最高)并找出频率最高的字母和 e 之间的区别。 在我的心理演练中这似乎是有道理的,但我的编译器出于某种原因给了我断点并且根本不允许我检查它,所以我不确定出了什么问题。所以请原谅我没有发布 SSCCE。在此先感谢您的帮助!
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
int alpharay[26];
for (int i = 0; i < 26; i++)
{
alpharay[i] = 0;
}
ifstream input;
cout << "File name (.txt): ";
string fileName;
cin >> fileName;
input.open(fileName.c_str());
while (!input.eof())
{
string newLine;
getline (input, newLine);
for (int i = 0; i < newLine.length(); i++)
{
if (isalpha(newLine[i]))
{
int index;
if (isupper(newLine[i]))
{
index = newLine[i] - 'A';
alpharay[index]++;
}
else if (islower (newLine[i]))
{
index = newLine[i] - 'a';
alpharay[index]++;
}
}
}
}
//To find the largest value in array
int largest = 0;
char popular;
for (int i = 0; i < 26; i++)
{
if (alpharay[i]>=largest)
{
largest = alpharay[i];
popular = 'a' + i;
}
}
//To find the size of the shift
int shift = popular - 'e';
cout << "Shift size: " << shift << endl;
return 0;
}
问题 1:
input.open(fileName.c_str());
while (!input.eof())
需要检查文件是否打开。如果文件打不开,您将永远不会收到 EOF。
input.open(fileName.c_str());
if (input.is_open()
{
while (!input.eof())
// rest of your code
}
else
{
cout << "Couldn't open file " << fileName << endl;
}
但这只是解决了问题。除了需要注意的 EOF 之外,文件可能发生的情况还有很多。
问题 2:
while (!input.eof())
{
string newLine;
getline (input, newLine);
for (int i = 0; i < newLine.length(); i++)
那么如果 getline 读到了 EOF 呢?该程序将其作为有效行进行处理,然后测试 EOF。同样,一个简单的修复:
string newLine;
while (getline (input, newLine))
{
for (int i = 0; i < newLine.length(); i++)
// rest of loop code
}
只要读完一行,就继续。如果没有行,不管为什么,循环退出。
问题 3:
如果没有字母字符,这个循环将 return 'z':
for (int i = 0; i < 26; i++)
{
if (alpharay[i]>=largest)
{
largest = alpharay[i];
popular = 'a' + i;
}
}
简单的解决方案是 运行 循环,然后测试最大的 == 0 并打印合适的 "No letters found" 消息。
在C++中我们不应该使用C-Style数组,而应该使用C++ STL容器。并且有许多容器可用于各种用途。
例如计算元素。
有一个或多或少的标准方法来计算容器中或一般情况下的东西。
我们可以使用关联容器,例如 std::map
或 std::unordered_map
。在这里,我们将一个“键”(在本例中为要计数的字母)与一个值(在本例中为特定字母的计数)相关联。
幸运的是地图有一个非常好的索引运算符[]。这将查找给定的键,如果找到,return 对该值的引用。如果未找到,它将使用键和 return 对新条目的引用创建一个新条目。因此,在机器人案例中,我们将获得对用于计数的值的引用。然后我们可以简单地写:
std::unordered_map<char,int> counter{};
counter[c]++;
这看起来非常直观。
另外。从地图中获取最大的计数器值,可以简单地通过使用 maxheap 来实现。可以使用 std::priority_queue
在 C++ 中实现最大堆。您可以使用它的范围构造函数,用 std::unordered_map
中的值填充它。所以,一个典型的单线。现在您可以立即访问最高价值。
这样,我们就可以得到一段非常紧凑的代码了。
#include <iostream>
#include <fstream>
#include <utility>
#include <unordered_map>
#include <queue>
#include <vector>
#include <iterator>
#include <string>
#include <cctype>
// Some Alias names to ease up typing work and to make code more readable
using Counter = std::unordered_map<char, int>;
struct Comp { bool operator ()(const std::pair<char, int>& p1, const std::pair<char, int>& p2) { return p1.second < p2.second; }};
using MaxHeap = std::priority_queue<std::pair<char, int>, std::vector<std::pair<char, int>>, Comp>;
int main() {
// Get filename, open file and check, if it could be opened
if (std::string fileName{}; std::getline(std::cin, fileName)) {
if (std::ifstream fileStream{ fileName }; fileStream) {
Counter counter{};
// Read all characters from the source file and count their occurence
for (char c{}; fileStream >> c;) {
// Get lower case of letter
const char letter = static_cast<char>(std::tolower(c));
// Count occurence, if letter is an alpha value
if (std::isalpha(letter)) counter[letter]++;
}
// Build a Max-Heap
MaxHeap maxHeap(counter.begin(), counter.end());
// Show result
std::cout << "\nShift size: " << maxHeap.top().first-'e' << '\n';
}
else std::cerr << "\nError: Could not open file '" << fileName << "'\n";
}
}
用 C++17 编译
为了轻松地按排序顺序访问所有元素,您还可以使用 std::multiset
而不是 std::priority
队列。
如果你只想拥有最顶层的 n 个元素,你可以将 std::partial_sort_copy
与 std::vector
结合使用。