Ответы:
Я предпочел бы it - vec.begin()
точно по противоположной причине, данной Naveen: чтобы он не компилировался, если вы измените вектор в список. Если вы делаете это во время каждой итерации, вы можете легко превратить алгоритм O (n) в алгоритм O (n ^ 2).
Другой вариант, если вы не будете прыгать в контейнере во время итерации, это сохранить индекс как счетчик второго цикла.
Примечание: it
это общее имя для итератора контейнера std::container_type::iterator it;
.
it
?
std::container_type::iterator it;
std::list
что не предлагает прямой доступ к элементам по их положению, поэтому, если вы не можете этого сделать list[5]
, вы не сможете этого сделать list.begin() + 5
.
Я бы предпочел, так std::distance(vec.begin(), it)
как это позволит мне изменить контейнер без каких-либо изменений кода. Например, если вы решите использовать std::list
вместо std::vector
которого не предоставляет итератор произвольного доступа, ваш код все равно будет компилироваться. Поскольку std :: distance выбирает оптимальный метод в зависимости от характеристик итератора, у вас также не будет никакого снижения производительности.
vec
- плохая новость. Если код был переписан так, чтобы он был универсальным, принимая тип контейнера в качестве параметра шаблона, тогда мы можем (и должны) поговорить об обработке итераторов без произвольного доступа ;-)
vec
тоже довольно плохая новость.
Как показали UncleBens и Naveen, для этого есть веские причины. Какой из них «лучше», зависит от того, какое поведение вы хотите: хотите ли вы гарантировать поведение в постоянном времени, или вы хотите, чтобы оно при необходимости возвращалось к линейному времени?
it - vec.begin()
занимает постоянное время, но operator -
определяется только на итераторах с произвольным доступом, поэтому, например, код вообще не будет компилироваться с итераторами списка.
std::distance(vec.begin(), it)
работает для всех типов итераторов, но будет работать только в постоянном времени, если используется на итераторах с произвольным доступом.
Ни один из них не "лучше". Используйте тот, который делает то, что вам нужно.
Мне нравится этот it - vec.begin()
, потому что мне ясно сказано «расстояние от начала». С итераторами мы привыкли мыслить в терминах арифметики, поэтому -
знак является самым ясным индикатором здесь.
distance
?
it++
а не что-то вроде std::increment(it)
, не так ли? Разве это не считается менее понятным?
++
Оператор определяется как часть STL последовательностей , как , как мы увеличиваем итератор. std::distance
вычисляет количество элементов между первым и последним элементом. Тот факт, что -
оператор работает, просто совпадение.
Если вы уже ограничены / зашиты ваш алгоритм с использованием std::vector::iterator
и std::vector::iterator
только, это действительно не имеет значения , какой метод вы будете в конечном итоге с помощью. Ваш алгоритм уже конкретизирован за пределами точки, где выбор одного из других может иметь любое значение. Они оба делают одно и то же. Это просто вопрос личных предпочтений. Я бы лично использовал явное вычитание.
Если, с другой стороны, вы хотите сохранить более высокую степень универсальности в вашем алгоритме, а именно, чтобы дать возможность того, что когда-нибудь в будущем он может быть применен к какому-либо другому типу итератора, тогда лучший метод зависит от вашего намерения , Это зависит от того, насколько вы хотите ограничить тип итератора, который можно использовать здесь.
Если вы используете явное вычитание, ваш алгоритм будет ограничен довольно узким классом итераторов: итераторами с произвольным доступом. (Это то, что вы получаете сейчас std::vector
)
Если вы используете distance
, ваш алгоритм будет поддерживать гораздо более широкий класс итераторов: входные итераторы.
Конечно, вычисление distance
для итераторов без произвольного доступа в общем случае является неэффективной операцией (хотя, опять же, для произвольных итераторов это так же эффективно, как вычитание). Вам решать, имеет ли ваш алгоритм смысл для итераторов без произвольного доступа с точки зрения эффективности. Если результирующая потеря эффективности опустошает вас до такой степени, что делает ваш алгоритм совершенно бесполезным, тогда вам лучше придерживаться вычитания, что запрещает неэффективное использование и вынуждает пользователя искать альтернативные решения для других типов итераторов. Если эффективность с итераторами без произвольного доступа все еще находится в пригодном для использования диапазоне, то вам следует использовать distance
и задокументировать тот факт, что алгоритм лучше работает с итераторами с произвольным доступом.
Согласно http://www.cplusplus.com/reference/std/iterator/distance/ , поскольку vec.begin()
это итератор с произвольным доступом , метод расстояния использует -
оператор.
Таким образом, ответ с точки зрения производительности - то же самое, но, возможно, использование distance()
легче понять, если кому-то придется читать и понимать ваш код.
Я бы использовал -
вариант std::vector
только - довольно ясно, что имеется в виду, и простота операции (которая не больше, чем вычитание указателя) выражается синтаксисом ( distance
с другой стороны, звучит как пифагор на первое чтение, не так ли?) Как указывает UncleBen, -
также действует как статическое утверждение на случай, если vector
он случайно изменился наlist
.
Кроме того, я думаю, что это гораздо более распространено - хотя у меня нет цифр, чтобы доказать это. Основной аргумент: it - vec.begin()
короче в исходном коде - меньше печатной работы, меньше занимаемого места. Поскольку ясно, что правильный ответ на ваш вопрос сводится к вкусу, это также может быть веским аргументом.
Вот пример, чтобы найти «все» вхождения 10 вместе с индексом. Думаю, это поможет.
void _find_all_test()
{
vector<int> ints;
int val;
while(cin >> val) ints.push_back(val);
vector<int>::iterator it;
it = ints.begin();
int count = ints.size();
do
{
it = find(it,ints.end(), 10);//assuming 10 as search element
cout << *it << " found at index " << count -(ints.end() - it) << endl;
}while(++it != ints.end());
}