Является ли это хорошим тоном сравнивать с изменяющимися значениями в цикле в C ++?

Несомненно, некоторые из вас видели мою недавнюю публикацию, посвященную одной и той же программе. Я постоянно сталкиваюсь с проблемами. Повторюсь: все еще учусь, не очень продвинутый, не очень хорошо понимаю указатели, не беру класс, вообще не понимаю концепций ООП и т. Д. Этот код просто объединяет два отсортированных вектора, farray и sarray, в один отсортированный вектор. По крайней мере, я надеюсь, что это то, что он делает. Скажите мне:

    //int num is to find the size of the original vector and
    //build up farray and sarray; not used in the merge process
    int num = original.size() 
    std::vector<int> final;

    std::vector<int>::iterator it = farray.begin();
    std::vector<int>::iterator iter = sarray.begin();

    //farray.size() == (0 thru (num / 2))
    //sarray.size() == ((num / 2) thru num)
    for (;it != farray.end() && iter != sarray.end();) {
        if (*it > *iter) {
            final.push_back(*it);
            it++;
        }    
        else
        {
            final.push_back(*iter);
            iter++;
        }

            if (it == farray.end()) {
                for (int i = 0; iter < sarray.end(); i++) {
                    final.push_back(*iter);
                }
            }

            if (iter == sarray.end()) {
                for (int i = 0; it < farray.end(); i++) {
                    final.push_back(*iter);
                }
            }
        }

Я переписал часть слияния моей функции сортировки слиянием, чтобы ... ну, чтобы она работала. На самом деле у меня есть несколько вопросов по этому коду:

  1. Является ли хорошим тоном сравнивать с std :: vector :: iterators it && iter для моих последних двух операторов if, если цикл for может изменить их на следующем проходе?
  2. Изменится ли значения iter и it на последнем проходе этого цикла и испортят ли мой код? Буду ли помещать мои последние операторы if перед сравнением * it и * iter?
  3. Обращается ли функция-член end () к последнему значению того, что ее вызывает? Кажется, что это могло как-то выйти за рамки этого.

РЕДАКТИРОВАТЬ: Я отвечу на все ответы завтра, так что загляните потом, если хотите услышать больше. Уже за полночь. Доброй ночи.


person jkeys    schedule 20.04.2009    source источник
comment
Циклы for в ваших последних двух операторах if кажутся неработающими - как написано, они просто будут увеличивать i бесконечно. Я полагаю, вы имели в виду что-то вроде for (; iter ‹sarray.end (); iter ++)   -  person goldPseudo    schedule 20.04.2009
comment
Вы правы, я просто привык иметь дело с массивами и стандартной системой итераций для них, чего я не продумывал.   -  person jkeys    schedule 20.04.2009


Ответы (5)


1. Можно сравнивать итераторы, которые находятся из того же контейнера, что и условие цикла for, но это имеет смысл только в том случае, если вы перемещаете один или другие итераторы либо в части приращения, если оператор цикла for, либо в теле самого цикла for. В этом цикле for вы сравниваете iter с sarray.end(), но цикл for никогда не изменяется iter. Это означает, что либо итераций не будет, либо цикл for никогда не завершится. Кроме того, вы, вероятно, захотите использовать для сравнения !=, а не <. == и != работают со всеми итераторами, < - нет.

            for (int i = 0; iter != sarray.end(); i++) {
                final.push_back(*iter);
            }

Поскольку iter начинается там, где вы хотите, чтобы цикл начинался, вам может понадобиться что-то вроде этого:

            for (; iter != sarray.end(); ++iter) {
                final.push_back(*iter);
            }

Поскольку вы все еще учитесь (хотя не все мы!), Вероятно, полезно поработать с таким алгоритмом, но вы должны знать std::merge, который, вероятно, делает то, что вы хотите.

std::merge( farray.begin(), farray.end(), sarray.begin(), sarray.end(), std::back_inserter( final ) );

(Вам нужно #include <iterator> и <algorithm>.)

2. Я не вижу увеличения iter или его во внешнем цикле for, что делает недействительной логику последующих циклов for, за исключением точки в 1..

3. end() указывает на один за концом контейнера, поэтому вы можете использовать его для проверок завершения цикла, но вам не следует пытаться разыменовать итератор с «==» на «.end()».

person CB Bailey    schedule 20.04.2009

Я не проверял реализацию вашего алгоритма, просто отвечу на три ваших вопроса:

  1. Итераторы очень похожи на указатели на значения контейнера. Это точно так же, как при использовании size_t i, а затем ++ i в цикле for. считаете ли вы, что сравнивать farray [i] с sarray [i] проблематично? наверное нет, поэтому все нормально.
  2. Я вижу, что вы делаете здесь в своем коде, что вы просто читаете значения * it и * iter, вы на самом деле их не меняете, поэтому они не изменятся.
  3. Конец () указывает на недопустимое место. Он указывает не на последнее значение, а на «после него». Это похоже на NULL, если вы это сделаете, поэтому, если (iter == sarray.end ()) истинно, вы получите сбой, если напишете * iter, потому что вы не можете разыменовать итератор, который равен end ().
person Gal Goldman    schedule 20.04.2009

Несколько общих советов: вам нужно подумать об именах переменных. Называя свои итераторы «it» и «iter», вы в какой-то момент запутаетесь. Собственно, если присмотреться, он уже есть. Если «farray» и «sarray» значимые имена, как насчет «fiter» и «siter».

Также подумайте, что делает сортировка слиянием. Эти последние два блока нужны только для того, чтобы «истощить» какой-либо итератор, у которого осталось что-то. Таким образом, им не нужно быть в первом цикле.

Я бы, наверное, написал это как (псевдокод):

while not (list1.empty and list2.empty):
    if list1.empty:
        result.push(list2.pop)
    else if list2.empty:
        result.push(list1.pop)
    else if list1.top > list2.top:
        result.push(list2.pop)
    else:
        result.push(list1.pop)

Или в несколько ржавом C ++, обработанном грузом:

std::vector<int>::iterator fiter = farray.begin();
std::vector<int>::iterator siter = sarray.begin();

while (fiter != farray.end() || siter != sarray.end()) {
    if (fiter == farray.end())      final.push_back(*siter++);
    else if (siter == sarray.end()) final.push_back(*fiter++);
    else if (*fiter > *siter)       final.push_back(*siter++);
    else                            final.push_back(*siter++);
}
person NickZoic    schedule 20.04.2009

Здесь есть о чем подумать.

Во-первых, если вы объединяете два диапазона, вам будет гораздо лучше использовать std: : merge вместо собственного.

Ваш код немного сложен для чтения, потому что вы используете разные стили для отступов и фигурных скобок. Выберите стиль и придерживайтесь его.

Первая часть вашего цикла for кажется правильной реализацией слияния:

for (;it != farray.end() && iter != sarray.end();) {
    if (*it > *iter) {
        final.push_back(*it);
        it++;
    }    
    else
    {
        final.push_back(*iter);
        iter++;
    }

... и это должно быть все, что вам нужно для выполнения работы.

Во второй части вашего цикла есть пара проблем:

   for (;it != farray.end() && iter != sarray.end();) {
         :   :
            if (it == farray.end()) {
                for (int i = 0; iter < sarray.end(); i++) {
                    final.push_back(*iter);
                }
            }

            if (iter == sarray.end()) {
                for (int i = 0; it < farray.end(); i++) {
                    final.push_back(*iter);
                }
            }
        }

Во-первых, условные выражения for () написаны так, что и it, и iter не должны указывать на end() их соответствующей коллекции, иначе цикл завершится. Таким образом, it никогда не может указывать на sarray.end(), iter никогда не может указывать на farray.end(), и ни один оператор if не может срабатывать. Оба они - мертвый (недоступный) код.

Но даже если это не мертвый код, в них есть ошибки. Условное выражение в for(...) прерывает цикл, когда итератор указывает на конец коллекции, но этот итератор никогда не перемещается, поэтому у вас есть бесконечный цикл.

Опять же, оба этих for(...) являются ненужным мертвым кодом, потому что итераторы никогда не могут указывать на конец вектора.

person John Dibling    schedule 20.04.2009
comment
Могу я просто вычесть 1 из каждого оператора if? if (it == farray.end () - 1), например. Есть ли причина, по которой это было бы плохо? - person jkeys; 20.04.2009
comment
На крючке: Чего вы пытаетесь достичь? - person John Dibling; 20.04.2009
comment
Что ж, я хочу отметить все значения farray и sarray. Если я достигну конца одного, потому что все они имеют меньшее значение по сравнению с другим, мне нужно будет добавить остальные более высокие значения в final. Я просто хочу, чтобы цикл шел от первого отсортированного номера последнего отсортированного массива к последнему номеру последнего отсортированного массива. - person jkeys; 20.04.2009
comment
Как вы построили цикл for (), он будет продолжаться только до тех пор, пока они оба не находятся в конце. Если какой-либо из них находится в конце, цикл for () завершится. Вам нужно перепроектировать это, чтобы обрабатывать входные коллекции разного размера, или просто используйте std :: merge (). :) - person John Dibling; 20.04.2009

Один простой комментарий: почему бы не использовать while (condition) вместо for(; !condition; ).

Последняя конструкция нестандартна и трудна для понимания!

person Andrew Jaffe    schedule 20.04.2009
comment
Я не согласен. Мне совсем не сложно читать, и для меня это более стандартно, чем использование while (). - person John Dibling; 20.04.2009