循环遍历向量<string>时出现问题,并保持每个元素的“计数”

时间:2017-05-19 02:19:57

标签: c++ c++11

首先,这是我在网站上的第一个问题。我已经做了很多研究,我认为我没有找到相当具体的问题,但如果我错了,请随时在答案中纠正我并将该主题与我联系起来。

在问题本身上,赋值包括一个控制台应用程序,它将显示输入的每个不同的单词,以及每个唯一单词的出现次数。我决定解决这个问题的方法是使用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次以上,因为只要在外部循环中遇到重复元素,该实例就会重复。

这是一张图片: Basic Result Promblem, Duplicate Output

我以为我会用以下代码解决它:

//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次以上的单词根本不显示,并返回错误。

这是一张图片:Updated problem, now duplicate values throw an error

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

5 个答案:

答案 0 :(得分:1)

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

因为减少循环中向量的大小会导致索引无效,这超出了向量的大小,但循环可能仍会以!=进行,而<将始终只考虑有效的指数。

在循环中仅将!=更改为<并且有效。

这是Output

修改

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

在删除元素后添加j--;即可。

这是新的Output

更正后的代码:

//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;
}

答案 1 :(得分:1)

让我们看一下您的示例案例失败的位置:

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) << " times\n";
    it = i;
}

您可以在此处看到此实例:http://ideone.com/Nhicos请注意,此代码不需要输入序列终止字,&#34; -end&#34;在你的情况下,而是取决于EOF。它会自动附加到http://ideone.com输入:Read cin till EOF

答案 2 :(得分:0)

我认为你应该检查 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;
}

答案 3 :(得分:0)

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

std::unordered_map

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

答案 4 :(得分:0)

<强>更新

在循环条件中将运算符!=简单更改为<是不够的。是的,两个案例工作正常,但如果有一个特定单词的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等等。

我想以这种方式解决问题(使用向量本身),因为教科书“Accelerated C ++”仅涵盖了向量和字符串。

请记住以下几点:

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

感谢所有发布在此的人的帮助!