Сравните два последовательных элемента в std::list

Я хотел бы сравнить два последовательных элемента в std::list при переборе списка. Как правильно получить доступ к элементу i+1, пока мой итератор находится в элементе i? Спасибо, Кобе.


person Community    schedule 04.11.2008    source источник
comment
Если возможно, вы можете изменить заголовок вопроса на Как сравнить ДВА последовательных элемента в std::list?. Я бы сделал это сам, но у меня нет репутации ;-)   -  person Tom Williams    schedule 04.11.2008


Ответы (4)


STL предоставляет алгоритм смежных_найти(), который можно использовать для поиска двух последовательных одинаковых элементов. Существует также версия с пользовательским предикатом.

Это прототипы:

template <class ForwardIterator>
   ForwardIterator adjacent_find ( ForwardIterator first, ForwardIterator last );

template <class ForwardIterator, class BinaryPredicate>
   ForwardIterator adjacent_find ( ForwardIterator first, ForwardIterator last,
                                   BinaryPredicate pred );
person Nicola Bonelli    schedule 04.11.2008
comment
Ваш ответ, который я хотел написать сам; Я надеюсь, что ОП примет ваш ответ. Хорошая вещь! +1 (хорошо бы +5, но сайт не позволяет) - person Chris Jester-Young; 04.11.2008

У Boost есть утилита под названием next (и ее обратная, prior) именно для этого. цель.

*itr == *next(itr)

Редактировать: Но если мы вернемся назад, чтобы взглянуть на лес, настоящий вопрос заключается в том, зачем писать свой собственный adjacent_find функция? (Я рекомендую принять ответ Николы Бонелли.) Это часть STL и не требует использования Boost, если ваш код не использует Boost (спасибо комментаторам за указание на это).

person Chris Jester-Young    schedule 04.11.2008
comment
Забавно, что почти каждый вопрос C++ на сайте совершенно другой, если у вас есть Boost и если вы ограничиваетесь стандартными ответами C++. Как будто это разные языки... - person Steve Jessop; 04.11.2008
comment
Я вот о том же подумал :) - person warren; 04.11.2008
comment
Это это как разные языки! Для меня Boost — это то, что делает C++ достойным использования. :-P Неиспользование Boost похоже на неиспользование SRFI при написании кода Scheme. :-П - person Chris Jester-Young; 04.11.2008
comment
C++11 теперь включает std::next и std::prev, что в данном случае делает бустинг ненужным. - person ; 27.04.2013

Проще всего было бы удерживать два итератора (поскольку вам все равно придется остановиться на предпоследнем).

std::list<int>::const_iterator second = list.begin(),
                               end = list.end();

if ( second != end ) // Treat empty list
    for(std::list<int>::const_iterator first = second++; // Post-increment 
        second != end; 
        ++first, ++second)
    {
        //...
    }

Обратите внимание, что first инициализируется с помощью пост-инкремента second, поэтому, когда цикл начинается first, это list.begin(), а второй - list.begin()+1.

Крис Джестер-Янг указывает, что у boost есть функции next и prior, хотя я не знаком с этими функциями (за свои грехи), их реализация тривиальна (особенно с учетом того, что list имеет двунаправленные итераторы).

template <class Iterator>
Iterator next(Iterator i) // Call by value, original is not changed
{ 
    return ++i;
}
// Implementing prior is left as an exercise to the reader ;o) 

Я чувствую, что использование next не решает эту проблему, а также поддержку обоих итераторов, поскольку вы должны помнить, что next(i) не равно end() при каждом использовании.


Правки:

  • Исправлена ​​ошибка, если список был пуст благодаря комментарию Luc Touraille.
  • Добавьте ссылку на next и почему я думаю, что это не подходит для этого варианта использования.
person Motti    schedule 04.11.2008
comment
К сожалению, после написания следующей реализации я вижу, что она точно такая же, как в ссылке, которую Крис включил в приветственный пост. - person Motti; 04.11.2008
comment
Ах, сила простых и очевидных решений! :-P Я все еще думаю, что смежный_найти - самое простое решение из всех, но да. - person Chris Jester-Young; 05.11.2008

Список является обратимым контейнером, поэтому его итераторы являются двунаправленными итераторами, которые являются моделью прямого итератора, что, я почти уверен, означает, что вы можете сделать это (или что-то подобное, если у вас аллергия на вырваться из середины петля и др.):

if (!l.empty()) {
    for (list<T>::const_iterator i = l.begin();;) {
        const T &a = *i;
        ++i;
        if (i == l.end()) break;
        do_comparison(a, *i);
    }
}

Вы не могли бы сделать это с помощью итератора ввода, потому что с ними значения «существуют» только до тех пор, пока у вас есть итератор. Но вы можете с Forward Iterator.

person Steve Jessop    schedule 04.11.2008