Найти элемент в векторе с предыдущим и следующим элементами, равными 0

#c #for-loop #vector

#c #для цикла #вектор

Вопрос:

Я хочу пройти через заданный вектор целых чисел и найти целое число, значение следующего и предыдущего целых чисел которого равно 0.

 #include <iostream>
#include <vector>

using namespace std;

int main()
{
    vector<int> sample = { 0,3,0 };
    for (int i : sample)
    {
        if (sample[i - 1] == sample[i   1] == 0)
        {
            cout << "hello";
        }
    }
}
 

Тем не менее, я продолжаю получать сообщение об ошибке «векторный индекс вне диапазона». Я думаю, это потому, что, когда i равно 0, sample[-1] не существует, то же самое с i = 2 .

Есть ли простое решение для этого?

Комментарии:

1. Вы имели в виду использовать цикл на основе индекса, например for (size_t i = 1; i < sample.size() - 1; i) ?

2. Вы неправильно понимаете диапазон for . i является значением sample , а не индексом. То есть значения i будут 0 , 3 , и 0 , соответственно, не 0 , 1 , и 2 . Однако ваше подозрение, что попытка доступа sample[-1] неверна, вполне обосновано, и когда вы переписываете код для использования индексов, вы должны позаботиться о том, чтобы избежать этого.

3. Ваше объяснение неверно. i присваивается 0 , 3 , 0 , а не 0 , 1 , 2 , поэтому использование его в качестве индекса в sample[i] не делает того, что вы думаете.

4. i не является значением от 0 до size-1. Это не индекс. i выполняется ли итерация текущего значения. Тогда значения i в этом случае будут 0 3 0 равны . Кроме того, ваша логика ошибочна, поскольку она предполагает, что каждый элемент является предыдущим и последующим элементом. Если бы это i был индекс, вы бы проверяли индексы out of bounds, когда i это первый или последний индекс в векторе.

5. Ранжированные циклы for, к сожалению, не позволяют вам использовать доступ к индексу элемента; Вы могли бы использовать итераторы, но не уверены, что вы уже узнали о них; в противном случае может работать «стандартный» цикл для цикла через индекс. if (sample.size() > 2u) { for (auto p1 = sample.begin(), p2 = p1 2; p2 != sample.end(); p1, p2) { if (*p1 == 0 amp;amp; *p2 == 0) { std::cout << "hello"; } }}

Ответ №1:

Здесь вы сталкиваетесь с двумя проблемами.

Во-первых, используя обозначение цикла range-for, переменная i соответствует значениям массива 0, 3 и 0. Не их индексы.

Вторая проблема заключается в том, что если вы выполняете итерацию от индекса 0 до конца, вы будете проверять индексы -1 и 3 , которые находятся за пределами вектора.

Вот код, который решает проблему двумя способами, первый использует индексы, а второй использует итераторы. Для второго вы эффективно обрабатываете p как указатель на текущий элемент в списке. Я сделал список немного длиннее, чтобы привести больше примеров. Он выводит целые 2 числа и 5 окружен нулями.

 #include <iostream>
#include <vector>

using namespace std;

int main()
{
    vector<int> sample = { 0, 3, 6, 0, 2, 0, 5, 0 };
    for(int i = 1; i < sample.size() - 1; i  ){
        if(sample[i-1] == 0 amp;amp; sample[i 1] == 0)
            cout << "integer " << sample[i] << " surrounded by 0n";
    }

    for(std::vector<int>::iterator p = sample.begin()   1; p != sample.end() - 1; p  ){
        if(*(p-1) == 0 amp;amp; *(p 1) == 0)
            cout << "integer " << *p << " surrounded by 0n";
    }
}
 

Для второго примера std::vector<int>::iterator часто заменяется на auto более короткое.

Ответ №2:

Этот диапазон основан на цикле for

 for (int i : sample)
{
    if (sample[i - 1] == sample[i   1] == 0)
    {
        cout << "hello";
    }
}
 

не имеет смысла, потому что в качестве индексов вектора используются значения вектора.

Цикл for, основанный на диапазоне, не подходит для такой задачи.

Вы можете использовать, например, стандартный алгоритм std::adjacent_find .

Вот демонстрационная программа.

 #include <iostream>
#include <vector>
#include <iterator>
#include <algorithm>

int main() 
{
    std::vector<int> v = { 0, 1, 0, 2, 0, 3, 0 };
    
    auto condition = []( const auto amp;a, const auto amp;b )
    {
        return a != 0 amp;amp; b == 0;
    };
    
    if ( not v.empty() )
    {
        for ( auto current = std::next( std::begin( v ) ), last = std::end( v ); 
          ( current = std::adjacent_find( current, std::end( v ), condition ) ) != last;
          std::advance( current, 2 ) )
        {
            if ( *std::prev( current ) == 0 )
            {
                std::cout << *prev( current ) << ", " 
                          << *current << ", " 
                          << *std::next( current ) << 'n';
            }
        }
    }       
    
    return 0;
}
 

Вывод программы

 0, 1, 0
0, 2, 0
0, 3, 0
 

Ответ №3:

В range-for цикле i устанавливается значение каждого элемента в массиве. Для него НЕ задан индекс каждого элемента, как вы предполагаете в настоящее время.

Вместо этого вам нужно использовать цикл на основе индексов:

 #include <iostream>
#include <vector>

using namespace std;

int main()
{
    vector<int> sample = ...;
    if (sample.size() > 2)
    {
        for (size_t i = 1; i < sample.size()-1;   i)
        {
            if (sample[i-1] == 0 amp;amp; sample[i 1] == 0)
            {
                cout << sample[i] << endl;
            }
        }
    }
}
 

В противном случае вместо этого используйте цикл на основе итератора:

 #include <iostream>
#include <vector>

using namespace std;

int main()
{
    vector<int> sample = ...;
    if (sample.size() > 2)
    {
        for (auto iter = sample.begin() 1; iter != sample.end()-1;   iter)
        {
            if (*(iter-1) == 0 amp;amp; *(iter 1) == 0)
            {
                cout << *iter << endl;
            }
        }
    }
}
 

Комментарии:

1. if (sample.size() > 2) в 1-м примере не требуется.

2. @Eugene поскольку для корректной работы цикла требуется не менее 3 элементов, имеет смысл проверить это заранее. По крайней мере, код требует if (sample.size() > 0) или if (!sample.empty()) для обеспечения того sample.size()-1 , чтобы это не переполнялось, иначе код будет иметь неопределенное поведение .