循环遍历向量<string>并保持每个元素"count"时出现问题

Issue when looping through a vector<string>, and keeping "count" of each element

本文关键字:问题 元素 count lt 向量 遍历 string gt 循环      更新时间:2023-10-16

首先,这是我在网站上的第一个问题。我做了很多研究,我认为我没有发现像这样的具体问题,但是如果我错了,请随时在答案中纠正我并将所述主题链接到我。

在问题本身上,作业由一个控制台应用程序组成,该应用程序将显示输入的每个不同单词,以及每个唯一单词的出现次数。我决定解决这个问题的方法是使用vector<string>,然后使用嵌套循环结构,其中外循环将表示每个唯一的单词并且内部循环将用于将外部循环中的单词与向量中的每个现有单词进行比较

然而。我遇到了一个问题。

使用此基本设置:

//Sort vector into alphabetical order
sort(words.begin(), words.end()); //this only sorts them alphabetically, but equal strings are "next" to each other
//Find unique values
for(string::size_type i=0; i != words.size(); i++) {
int count = 0;
for(string::size_type j=0; j != words.size(); j++) {
if(words[i] == words[j]){
count++;
}
}
cout << words[i] << " appeared: " << count << " times." << endl;
}

就功能而言,一切正常;正确发现了单词的 2+ 个实例,但它们作为自己的行显示 2+ 次,因为每当在外部循环中遇到重复元素时,实例都会重复自己。

这是一张图片: 基本结果 问题,重复输出

我想我会用下面的代码来解决它:

//Sort vector into alphabetical order
sort(words.begin(), words.end()); //this only sorts them alphabetically, but equal strings are "next" to each other
//Find unique values
for(string::size_type i=0; i != words.size(); i++) {
int count = 0;
for(string::size_type j=0; j != words.size(); j++) {
if(words[i] == words[j]){
count++;
if(i != j){ //replacement: delete duplicate values from the vector (aka if the indexes don't match)
words.erase(words.begin() + j); //delete element at index "j"
}
}
}
cout << words[i] << " appeared: " << count << " times." << endl;
}

随之而来的是一个新问题:出现 2+ 次的单词现在抛出错误。索引本身可以正常工作,即如果我在删除元素后立即添加cout << words[i] << endl;,它会显示正确的单词。但是,出现 2+ 次的单词根本不显示,并返回错误。

这是一张图片:更新了问题,现在重复值抛出错误

任何人都会很好地解释为什么会发生这种情况,以及如何解决它?

让我们看看您的示例案例失败的地方:

for(string::size_type j=0; j != words.size(); j++) { // i: 1, j: 2, size(words): 3
if(words[i] == words[j]){ // words[i] matches words[j]
count++;
if(i != j){ // i doesn't match j
words.erase(words.begin() + j); // i: 1, j: 2, size(words): 2
}
}
} // Upon rexecuting the iteration expression i: 1, j: 3, size(words): 2 thus `j` will be greater than `size(words)` and will be used to continue the loop even though it is an invalid index

已经提供了几种解决方案来使用您当前的代码来解决此问题。但我建议解决此问题的最简单方法是multiset

const multiset<string> words{istream_iterator<string>(cin), istream_iterator<string>()};
auto it = cbegin(words);
while(it != cend(words)) {
auto i = words.upper_bound(*it);
cout << *it << " appeared: " << distance(it, i) << " timesn";
it = i;
}

您可以在此处看到一个实时示例: http://ideone.com/Nhicos 请注意,此代码无需输入序列终止字"-end",而是依赖于 EOF。 它会自动附加到 http://ideone.com 输入: 读取 cin 直到 EOF

您的代码是正确的,您只需要检查循环中的<而不是!=

因为减小循环中向量的大小可能会导致出现无效索引,这超出了向量的大小,但循环仍可能随!=<将始终仅考虑有效索引。

仅将!=更改为循环中的<,它就可以工作。

这是输出。

编辑:

您还需要重置j以检查下一个元素位于擦除元素的相同位置,因为现在下一个元素位于该位置而不是j + 1

只需在擦除元素后添加j--;即可。

这是新的输出。

更正的代码:

//Sort vector into alphabetical order
sort(words.begin(), words.end()); //this only sorts them alphabetically, but equal strings are "next" to each other
//Find unique values
for(string::size_type i=0; i < words.size(); i++) {
int count = 0;
for(string::size_type j=0; j < words.size(); j++) {
if(words[i] == words[j]){
count++;
if(i != j){ //replacement: delete duplicate values from the vector (aka if the indexes don't match)
words.erase(words.begin() + j); //delete element at index "j"
j--; // Re-run iteration for j
}
}
}
cout << words[i] << " appeared: " << count << " times." << endl;
}

我想你应该检查一下i!=j;如果i==j它与自身进行比较。

//Find unique values
for(string::size_type i=0; i != words.size(); i++) {
int count = 0;
for(string::size_type j=0; j != words.size(); j++) {
if(words[i] == words[j]&&i!=j){
count++;
}
}
cout << words[i] << " appeared: " << count << " times." << endl;
}

这个问题可以使用称为哈希表的数据结构轻松解决。哈希表是一个包含键值对的关联数组。基本上,"键"(可以是单词)用于计算保存"值"的数组的索引,在您的实例中,该索引可以是它被计数的次数。C++有

std::unordered_map

这是一个哈希表。看看哈希表背后的理论:https://en.wikipedia.org/wiki/Hash_table 并在此处查找C++版本: http://www.cplusplus.com/reference/unordered_map/unordered_map/这应该使您的程序更容易编写。当输入值为 1 的单词时,您只需将单词添加到哈希表中即可。当您再次看到该单词时,递增其关联值。

更新:

在循环条件下,简单地将操作员!=更改为<是不够的。是的,两种情况工作正常,但如果特定单词有 3+ 个实例,则输出将分成几行。我可以用我迄今为止有限的知识提供的解释是,内部循环正在检查条件"来自外部循环的索引是否等于来自内部循环的索引",这在理论上应该可以正常工作。但是,由于在 2+ 实例中,数组中至少删除了 1 个元素,因此将单独评估条件,而不是一起计算。

经过一番推理,我能够提出最终解决方案:

//Sort vector into alphabetical order
sort(words.begin(), words.end()); //this only sorts them alphabetically, but equal strings are "next" to each other
//Find unique values
for(string::size_type i=0; i < words.size(); i++) {
int count = 0;
//duplicate vector, and use it for the inner loop
vector<string> duplicate = words;
for(string::size_type j=0; j < duplicate.size(); j++) {
if(words[i] == words[j]){
count++;
if(i != j){ //replacement: delete duplicate values from the vector (aka if the indexes don't match)
words.erase(words.begin() + j); //delete element at index "j"
}
}
}
cout << words[i] << " appeared: " << count << " times." << endl;
}

这实际上适用于任何类型的实例情况,无论是 2、3、5 等。

我想以这种方式解决问题(使用向量本身),因为教科书"加速C++"到目前为止只涵盖了向量和字符串。

请记住以下几点:

  • 作为一个新手程序员,进一步优化很可能是一个选择
  • 如果您对迄今为止最准确/简单/最有效的答案感兴趣,请查看@Jonathan我的答案,它仍然应该被投票为正确答案。

感谢所有在这里发帖的人的帮助!